Akk*_*i J 16 c# oop overriding member-hiding
任何人都可以在内存和引用方面告诉覆盖和隐藏的工作.
class A
{
public virtual void Test1() { //Impl 1}
public virtual void Test2() { //Impl 2}
}
class B : A
{
public override void Test1() { //Impl 3}
public new void Test2() { Impl 4}
}
static Main()
{
A aa=new B() //This will give memory to B
aa.Test1(); //What happens in terms of memory when this executes
aa.Test2(); //-----------------------SAME------------------------
}
Run Code Online (Sandbox Code Playgroud)
这里的内存是B类,但在第二个语句中,将调用aa.Test2类A的方法.为什么?如果B有内存,则应调用B的方法(在我看来).
任何非常深刻和完全描述这一基础的链接/练习将是一个很大的帮助.
Raw*_*ing 27
看看Eric Lippert 对这个问题的回答.
为了解释(达到我的理解的极限),这些方法进入"槽".A有两个插槽:一个用于Test1,一个用于Test2.
由于A.Test1被标记为virtual并被B.Test1标记为override,所以B实现Test1不会创建自己的插槽而是覆盖其A实现.无论您将实例B视为a B还是将其转换为a A,同一实现都在该插槽中,因此您始终可以得到结果B.Test1.
相比之下,由于B.Test2标记new,它创建了自己的新插槽.(如果它没有被标记,new但被赋予了不同的名称,那就好了.)它A的实现Test2仍然在它自己的插槽中"存在"; 它被隐藏而不是被覆盖.如果你把一个实例B视为a B,你会得到B.Test2; 如果你把它投射到一个A,你看不到新的插槽,A.Test2并被调用.
要添加@Rolling的答案,可以使用如下示例显示实际示例:
class Base
{
// base property
public virtual string Name
{
get { return "Base"; }
}
}
class Overriden : Base
{
// overriden property
public override string Name
{
get { return "Overriden"; }
}
}
class New : Base
{
// new property, hides the base property
public new string Name
{
get { return "New"; }
}
}
Run Code Online (Sandbox Code Playgroud)
1.压倒一切
在overriden属性的情况下,基类的虚方法槽由不同的实现替换.编译器将该方法视为虚拟,并且必须使用对象的虚拟表在运行时解析其实现.
{
Base b = new Base();
Console.WriteLine(b.Name); // prints "Base"
b = new Overriden();
// Base.Name is virtual, so the vtable determines its implementation
Console.WriteLine(b.Name); // prints "Overriden"
Overriden o = new Overriden();
// Overriden.Name is virtual, so the vtable determines its implementation
Console.WriteLine(o.Name); // prints "Overriden"
}
Run Code Online (Sandbox Code Playgroud)
2.隐藏
使用关键字隐藏方法或属性时new,编译器仅为派生类创建新的非虚方法; 基类的方法保持不变.
如果变量的类型是Base(即仅包含虚方法),则其实现将通过vtable解析.如果变量的类型是New,则将调用非虚方法或属性.
{
Base b = new Base();
Console.WriteLine(b.Name); // prints "Base"
b = new New();
// type of `b` variable is `Base`, and `Base.Name` is virtual,
// so compiler resolves its implementation through the virtual table
Console.WriteLine(b.Name); // prints "Base"
New n = new New();
// type of `n` variable is `New`, and `New.Name` is not virtual,
// so compiler sees `n.Name` as a completely different property
Console.WriteLine(n.Name); // prints "New"
}
Run Code Online (Sandbox Code Playgroud)
3.总结
如果代码的一部分接受基类型,它将始终在运行时使用虚拟表.对于大多数OOP场景,这意味着将方法标记new为非常类似于给它一个完全不同的名称.
4.实例化后的对象大小
请注意,实例化任何这些类型都不会创建虚拟表的副本.每个.NET对象都有几个字节的头和一个指向其类型(class)的表的虚拟表的指针.
关于new属性(非虚拟的),它基本上被编译为具有thiscall语义的静态方法,这意味着它也不会向内存中的实例大小添加任何内容.