class Program
{
static void Main(string[] args)
{
Person stu = new Student();
stu.work();
Console.ReadKey();
}
}
class Person
{
public virtual void work()
{
Console.WriteLine("我正在工作");
}
}
class Student : Person
{
public new void work() {
Console.WriteLine("我正在认真学习");
}
}
问题:
1:stu是person的对象还是student的对象?stu.work();调用的到底是person的方法还是student的方法。2:把new换成override,输出结果变成“我正在认真学习”,请解释
{
static void Main(string[] args)
{
Person stu = new Student();
stu.work();
Console.ReadKey();
}
}
class Person
{
public virtual void work()
{
Console.WriteLine("我正在工作");
}
}
class Student : Person
{
public new void work() {
Console.WriteLine("我正在认真学习");
}
}
问题:
1:stu是person的对象还是student的对象?stu.work();调用的到底是person的方法还是student的方法。2:把new换成override,输出结果变成“我正在认真学习”,请解释
解决方案 »
- 如何实现此类功能-》区域填充颜色
- C#开发opengl用CsGL还是用Csopengl还是Tao framework,那个能够紧跟opengl的版本?
- 怎样才能知道SQL服务是否有启动?
- 如何实现远程连接服务器
- 如何用四个线程在不同位置读写同一文件??
- 欢迎加入.NET高手-》成长群:14282006 (不容错过 顶者有分)
- 在调用数据库执行过程中(时间长),做一个正在执行的gif动画?有没办法?
- TEXTBOX中如何将光标定位在选定文本的第一个字符前,就象用鼠标向左面拖动选择文本后的效果???
- 请教学习c#的入门书籍,本人有一定的c++的基础
- 我现在开始学c#介绍几本好书吧,谢谢了,急用!!
- StreamReader读取乱码的问题
- C#如何自绘菜单的下拉边框?
override是复写基类成员隐藏仅对当前类有效
复写后 当调用此方法时 会自动调用该方法的最派生版本
若参数相同,基类函数有virtual关键字。如果基类函数有多个重载版本,且派生类并没有重写所有的同名虚函数,当在派生类中调用函数时,基类中未被重写的虚函数将被隐藏
http://www.cnblogs.com/hsapphire/archive/2009/12/16/1625365.html
解释:stu实例化时是通过new Student()实现的,所以必然是student的对象
student中的new work导致在student中会存在两个work方法的地址,具体执行哪个就要看当前声明的类型了。
如果是override work的话只在student中只会存在一个work方法的地址,已经将父类的work覆盖掉了,所以不管当前声明的是什么类型都会执行覆盖后的这个新的(stu已经看不到旧的了)。
class Program
{
static void Main(string[] args)
{
Person stu = new Student();
stu.work();
Console.ReadKey();
}
}
class Person
{
public void A() //把work换成A了
{
Console.WriteLine("我正在工作");
}
}
class Student : Person
{
public void work()
{
Console.WriteLine("我正在认真学习");
}
}
为什么又要报错呢?说person中没有work,既然是student的对象,就应该调student的work呀,
{
static void Main(string[] args)
{
Person stu = new GoodStudent();
stu.work();
((Student)stu).work();
((GoodStudent)stu).work();
Console.ReadKey();
}
}
class Person
{
public virtual void work()
{
Console.WriteLine("我正在工作");
}
}
class Student : Person
{
public new void work()
{
Console.WriteLine("我正在认真学习");
}
}
class GoodStudent : Student
{
public new void work()
{
Console.WriteLine("我都学会了,玩呢");
}
}试试这段代码你就更明白了,同一个对象拥有了多个方法地址,会根据当前声明的类型选择执行
stu.work,说明我想执行父类的方法,那么,直接写成Person stu = new person();不就得了吗,写成Person stu = new Student();有什么实际意义呢,请问?
class Program
{
static void Main(string[] args)
{
GoodStudent stu = new GoodStudent();
((Person)stu).work();
((Student)stu).work();
((GoodStudent)stu).work();
Console.ReadKey();
}
}
class Person
{
public virtual void work()
{
Console.WriteLine("我正在工作");
}
}
class Student : Person
{
public new void work()
{
Console.WriteLine("我正在认真学习");
}
}
class GoodStudent : Student
{
public new void work()
{
Console.WriteLine("我都学会了,玩呢");
}
}
这个问题应该是编译的问题吧
根本无法通过编译了stu 是被定义为 Person 类型然后 stu = new Student(); 这个时候stu的类型应该是Student()
但是stu 也有可能 被赋予 stu = new Person()
这个时候stu 就不能.work();
所以为了避免这种情况(stu变量对象改变)的发生 就不允许编译了以上....是我自己的理解
1.stu的类型是Person,新建了一个Student实例;
stu.work();这句在这里是调用了父类Person的work方法。
2.将new改为override,调用了子类的work方法。
可以理解为override是还用父类的方法,但是是重写父类的相同名称的方法的内容。
new是覆盖了父类的相同名称的方法。不恰当的比方就是:
override就是朝鲜的金老胖子,金胖子和金小胖子,还是他们金家的
new就是中华民国 和 RPC,都是中国,性质变了,覆盖掉了
比如有2个类 继承Person
Student:Person
Teacher:Person然后有一段代码
Person p;
if(i == 1)
{
p = new Student();
}
else
{
p = new Teacher();
}p.work();
这个时候你是不是知道为什么要这样写了呢
一个是“变量”的类型(或者说申明的类型)Person
一个是“变量引用的对象”的类型(或者说对象的实际类型)Student
虽然实际是 Student,但编译器只认 Person
一般直接写 Person stu = new Student(); 比较少,多在方法参数中这么用,比如:
void WorkAWeek( Person p )
{
for( int i = 0; i < 5; ++ i );
p.Work();
p.Rest(); // 假设 Person 有个 Rest 方法显示“我在休息”
p.Rest();
}如果 Student 正确 override 了 Work 这个方法,那么 WorkAWeek( new Student() ); 就会显示五遍“我正在认真学习”和两遍“我在休息”另一方面,假设 Student 有个方法 Exam 而 Person 中没有,那么你用 p.Exam() 必然会报错,因为编译器只知道 p 是 Person,即便有 p = new Student() 它也是不认的。
这个图是错误的。你从哪里淘弄来的烂图?f指向的就是一个Apple实例,只不过这个变量被声明为Fruit类型,于是编译器会按照这个类型来检查你的代码使用类型接口时的一致性。说Apple实例中嵌有一个独立的Fruit实例对象,是极端错误的。一个Apple实例就是一个Apple实例,它的接口是从Fruit继承而来,就好象女人是人,有着相同的嘴巴和眼睛接口,而不是说女人身体里边还有另外一个人。
至于 Apple 和 Fruit 的关系,虽然我也喜欢只有接口那种干干净净的方式,可惜目前大部分语言的继承就是把成员、实现一并继承下来的
接下来我们来看Apple a = new Fruit();这一句。首先Apple a在堆栈里创建了一个a指针,它准备指向一个实例。接下来new Fruit()它会在托管堆里面创建一个Fruit类实例,然后想把Fruit这个实例赋给a这个指针,显然由于Fruit类并不包含Apple类里面所包含特有的内容,这个时候把它赋给一个Apple a这样做是不行的。所以呢,导致这个语句失败。
我们可以这样去理解,打个比方,可以说苹果是一种水果,但是呢,不能说水果是一种苹果。假如CLR允许随便的转型,比如说一种类型随便转换成另外一种类型,这样呢就会违反安全性原则,将出现难以预料的结果。其中包括应用程序崩溃,以及造成安全漏洞。因为一种类型能轻松地伪装成另一种类型,类型伪装是造成许多安全漏洞的根源,并会破坏应用程序的稳定性和可靠性。因此,类型安全性是CLR一个极其重要的目标。
这个作者大概受C++影响比较大吧?这张图用来说明C++的继承实现比较接近,用来说明C#的继承实现就有一定距离了
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
// Person stu = new Student();
Student stu = new Student();
student1 stu1 = new student1();
Person p = stu; //编译时类型为person ,运行时类型为student。
p.work();
Person p1 = stu1; //编译时类型为person ,运行时类型为student1。
p1.work();
Console.ReadKey();
}
class Person
{
public virtual void work()//虚方法
{
Console.WriteLine("我正在工作");
}
}
class Student : Person
{
new public void work()//隐藏了继承而来的方法work
{
Console.WriteLine("我正在学习");
}
} class student1 : Person
{
public override void work()//重写了继承而来的方法work
{
Console.WriteLine("我正在认真玩");
}
}
}
}
结果是:
我正在工作 //基类的方法
我正在认真玩 //子类的方法所以当子类没有重写(override)基类的虚方法时,调用方法时,是根据该实例的编译时类型即person,
当子类重写的时候,对象的运行时类型是决定因素。即student1