class Father
{
public virtual void Fun(){} public void Method(){}
}class Sun
{
public override void Fun(){} // 重写父类的 Fun 方法 pbblic new void Method(){} // 隐藏父类的 Method 方法
}
比如上面这个例子
1. 关于 Fun 方法其实是子类在虚方法表中用新的 Fun 入口地址替换了继承的父类的 Fun 的地址;
2. 关于 Method ,烦请解释下在虚方法表中的是怎么操作的?能有什么权威的资料可以查查,谢谢!
class A
{
public void F()
{
Console.WriteLine("A.F");
}
}
class B: A
{
new public void F()
{
Console.WriteLine("B.F");
}
}
class Test
{
static void Main(string[] args)
{
B b = new B();
b.F();
A a = b;
a.F();
}
} 输出为 B.F A.F C#重写virtual(虚方法)示例 01.using System;
class A
{
public virtual void F()
{
Console.WriteLine("A.F");
}
}
class B: A
{
public override void F()
{
Console.WriteLine("B.F");
}
}
class Test
{
static void Main()
{
B b = new B();
b.F();
A a = b;
a.F();
}
} 输出为 B.F B.F补充:重写override一般用于接口实现和继承类的方法改写,要注意1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
pbblic new void Method(){} // 隐藏父类的 Method 方法
因为不是虚方法,所以此函数不会出现在虚方法表中。
如果一个类或其基类没有虚函数,那么这个类也不存在虚方法表。
同意你对public new void Method(){}的解释
但我认为一个类或者基类不管有没有虚函数,都存在虚方法表!补充:
如果子类不写这个函数,那么调用子类的Method,实际上是调用父类的Method的地址
子类写new void Method(){},实际上是告诉编译器这个时候要调用子类自己的Method的地址
这样就实现了隐藏父类的Method方法的目的
虚方法表(virtual method table):当生成一个对象时,编译器将类对象的前四个字节设置为虚方法表的地址,构造过程中先构造基类,为基类对象填表,再构造子类,为子类(本层次)的虚表填表,这样,在构造函数中调用虚方法是不是发生多态(本层次的多态)的;当然,在C#中,我试过,和C++完全不一样,可以产生多态
如果你有资料,可否共享一下?谢谢!
调用父类的Method地址并不等于调用虚方法表,这点我同意6楼的说法,有虚方法时才需要维护虚方法表的,这点和C++一样的概念,Thinking of C++中就有提到,由于这点的存在,使用虚方法带来的是效率的下降。但是换来了一个多态,还是划算的。
普通继承或是虚继承还是有关的,两者的顺序不同,至于C#的构造分析,可以看
《.Net2.0面向对象编程解密》记得有对CLR的构造顺序和方法表作过具体的分析,我手头没书,不记得具体的说法了
在方法表中包含了一个槽表,指向各个方法的描述(MethodDesc),提供了类型的行为能力。方法槽表是基于方法实现的线性链表,按照如下顺序排列:继承的虚方法,引入的虚方法,实例方法,静态方法。类加载器在当前类,父类和接口的元数据中遍历,然后创建方法表。在排列过程中,它替换所有的被覆盖的虚方法和被隐藏的父类方法,创建新的槽,在需要时复制槽。槽复制是必需的,它可以让每个接口有自己的最小的vtable。但是被复制的槽指向相同的物理实现。
谢谢分享。