要添加到@Rawling 的答案,可以使用以下示例显示实际示例:
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"; }
}
}
1. 压倒一切
在覆盖属性的情况下,基类的虚拟方法的插槽被不同的实现替换。编译器将该方法视为virtual,并且必须在运行时使用对象的虚拟表解析其实现。
{
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"
}
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"
}
三、总结
如果您的代码的一部分接受基本类型,它将在运行时始终使用虚拟表。对于大多数 OOP 场景,这意味着将方法标记为new
与给它一个完全不同的名称非常相似。
4. 实例化后的对象大小
请注意,实例化任何这些类型都不会创建虚拟表的副本。每个 .NET 对象都有几个字节的标头和一个指向其类型表的虚拟表的指针 ( class
)。
关于new
属性(不是虚拟的),它基本上被编译为具有 thiscall 语义的静态方法,这意味着它也不会增加内存中实例的大小。