Parent.F
Child.F
Child.G
Child.G
Child.F
Child.G
Child.G
解决方案 »
- OpenFileDialog1_FileOk事件问题
- 如何返回类方法的变量?
- 求代码!急用啊!
- log4net如何只保留5天之内的数据?
- c# 如何操作Excel
- c#定时备份数据库
- 请教一下,关于利用command读取信息,如果进行创建表?
- 自己比较笨!关于字节的问题
- SELECT FixtureID, Opponents + ' - ' + CONVERT (varchar, FixtureDate, 6) AS Fixture FROM Fixtures ORDER BY FixtureDate
- UdpClient.Receive(RemoteIpEndPoint)怎么不能得到对端的IP与PORT?
- 求助 部署工程 如何在 非web安装项目中不让用户指定路径。
- 关于多文档的菜单快捷键的问题,请指教
Child.F
Child.G
Child.G关注原因
Child.F
Child.G
Child.G
G是虚函数
Parent a = b;
此时a的类型是什么?是Child?为什么?
Child.F
Child.G---**********
Child.G*********
G是虚函数,在Child b = new Child();的时候,G()已经被重写了,再到Parent a = b;的时候,还是掉用了重写过后的G();这个是多态性。
*********
若一个实例方法的声明中含有 virtual 修饰符,则称该方法为虚拟方法。若其中没有 virtual 修饰符,则称该方法为非虚拟方法。非虚拟方法的实现是不会变的:无论是在声明它的类的实例上调用该方法还是在派生类的实例上调用,实现都是相同的。与此相反,一个虚拟方法的实现可以由派生类取代。取代所继承的虚拟方法的实现的过程称为重写该方法(第 10.5.4 节)。在一个虚拟方法调用中,该调用所涉及的那个实例的运行时类型确定了要被调用的究竟是该方法的哪一个实现。在非虚拟方法调用中,相关的实例的编译时类型是决定性因素。准确地说,当在具有编译时类型 C 和运行时类型 R 的实例(其中 R 为 C 或者从 C 派生的类)上用参数列表 A 调用名为 N 的方法时,调用按下述规则处理: 首先,将重载决策应用于 C、N 和 A,以从在 C 中声明的和由 C 继承的方法集中选择一个特定的方法 M。第 7.5.5.1 节对此进行了描述。
然后,如果 M 为非虚拟方法,则调用 M。
否则(M 为虚拟方法),就会调用就 R 而言 M 的派生程度最大的那个实现。
对于在一个类中声明的或者由类继承的每个虚拟方法,存在一个就该类而言的派生程度最大的实现。就类 R 而言虚拟方法 M 的派生度最大的实现按下述规则确定: 如果 R 中含有关于 M 的 virtual 声明,则这是 M 的派生程度最大的实现。
否则,如果 R 中含有关于 M 的 override 声明,则这是 M 的派生程度最大的实现。
否则,就 R 而言 M 的派生程度最大的实现与就 R 的直接基类而言 M 的派生程度最大的实现相同。
下列实例阐释虚拟方法和非虚拟方法之间的区别:using System;
class A
{
public void F() { Console.WriteLine("A.F"); }
public virtual void G() { Console.WriteLine("A.G"); }
}
class B: A
{
new public void F() { Console.WriteLine("B.F"); }
public override void G() { Console.WriteLine("B.G"); }
}
class Test
{
static void Main() {
B b = new B();
A a = b;
a.F();
b.F();
a.G();
b.G();
}
}
在该示例中,A 引入一个非虚拟方法 F 和一个虚拟方法 G。类 B 引入一个新的非虚拟方法 F,从而隐藏了继承的 F,并且还重写了继承的方法 G。此例产生输出:A.F
B.F
B.G
B.G
请注意,语句 a.G() 实际调用的是 B.G 而不是 A.G。这是因为,对调用哪个实际方法实现起决定作用的是该实例的运行时类型(即 B),而不是该实例的编译时类型(即 A)。由于一个类中声明的方法可以隐藏继承来的方法,因此同一个类中可以包含若干个具有相同签名的虚拟方法。这不会造成多义性问题,因为除派生程度最大的那个方法外,其他方法都被隐藏起来了。在下面的示例中using System;
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B: A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C: B
{
new public virtual void F() { Console.WriteLine("C.F"); }
}
class D: C
{
public override void F() { Console.WriteLine("D.F"); }
}
class Test
{
static void Main() {
D d = new D();
A a = d;
B b = d;
C c = d;
a.F();
b.F();
c.F();
d.F();
}
}
C 类和 D 类均含有两个具有相同签名的虚拟方法:A 引入的虚拟方法和 C 引入的虚拟方法。但是,由 C 引入的方法隐藏了从 A 继承的方法。因此,D 中的重写声明所重写的是由 C 引入的方法,D 不可能重写由 A 引入的方法。此例产生输出:B.F
B.F
D.F
D.F
请注意,通过访问 D 的实例(借助一个派生程度较小的类型,它的方法没有被隐藏起来),可以调用被隐藏的虚拟方法。
Child.F
Child.G
Child.G
G()为虚函数,
在C++中看一下基类指针指向派生类的相关知识
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B: A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C: B
{
new public virtual void F() { Console.WriteLine("C.F"); }
}
class D: C
{
public override void F() { Console.WriteLine("D.F"); }
}
class Test
{
static void Main() {
D d = new D();
A a = d;
B b = d;
C c = d;
a.F();
b.F();
c.F();
d.F();
}
}为什么输出结果是:
B.F
B.F
D.F
D.F
而不是
D.F
D.F
D.F
D.F
new public void F() { Console.WriteLine("Child.F"); }
G()本来就是虚函数,在子类实例化的过程中进行了动态绑定,所以以子类或超类的方式调用返回的结果都是重载后的函数的结果。
public override void G() { Console.WriteLine("Child.G"); }================
a.F();//Parent.F
b.F();//Child.F
a.G();//Child.G
b.G();//Child.G
==================