覆盖和隐藏之间的确切区别

任何人都可以在内存和引用方面告诉覆盖和隐藏的工作。

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------------------------ } 

这里的内存是B类,但在第二个语句中,将调用aa.Test2类A的方法。 为什么? 如果B有内存,则应调用B的方法(在我看来)。

任何非常深刻和完全描述这一基础的链接/练习将是一个很大的帮助。

看看Eric Lippert 对这个问题的回答 。

为了解释(达到我理解的极限),这些方法进入“插槽”。 A有两个插槽:一个用于Test1 ,另一个用于Test2

由于A.Test1被标记为virtualB.Test1被标记为override ,因此BTest1实现不会创建自己的插槽,而是覆盖A的实现。 无论您将B的实例视为B还是将其转换为A ,相同的实现都在该插槽中,因此您始终可以获得B.Test1的结果。

相比之下,由于B.Test2被标记为new ,它创建了自己的槽。 (如果它没有被标记为new但是被赋予了不同的名称,那就是它。) Test2的实现仍然在它自己的插槽中“存在”; 它被隐藏而不是被覆盖。 如果将B的实例视为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"; } } } 

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" } 

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" } 

3.总结

如果代码的一部分接受基类型,它将始终在运行时使用虚拟表。 对于大多数OOP场景,这意味着将方法标记为new方法非常类似于为其提供完全不同的名称。

4.实例化后的对象大小

请注意, 实例化这些类型中的任何一种都不会创建虚拟表的副本。 每个.NET对象都有几个字节的头和一个指向其类型( class )的表的虚拟表的指针。

关于new属性(非虚拟属性),它基本上被编译为具有thiscall语义的静态方法,这意味着它也不会在内存中添加任何大小的实例。

已经在这里回答了

覆盖是相同方法签名的多个可能实现的定义,这样实现由第0个参数的运行时类型决定(通常由C#中的名称标识)。

隐藏是派生类型中方法的定义,其签名与其基本类型中的签名相同,而不会覆盖。

覆盖和隐藏之间实际区别如下:

隐藏适用于所有其他成员(静态方法,实例成员,静态成员)。 它基于早期绑定。 更清楚的是,在编译期间决定要调用或使用的方法或成员。

•如果重写方法,则要调用的实现基于参数的运行时类型。 •如果只隐藏方法,则要调用的实现基于参数this的编译时类型。

以下是一些示例: 示例#1 。 和例子#2

类A中的Test1()方法和类B中的test1()方法将根据MethdOverriding执行。

类A中的Test2()方法和类B中的test2()方法将根据方法隐藏执行。

在方法中重写子类成员将执行,并且在方法隐藏中 ,父类成员将执行。

简单地说,当覆盖方法或属性时,覆盖方法必须与基本方法具有相同的签名。 当隐藏它不是必需的时,新对象可以采用如下所示的任何forms

 // base public int GrossAmount { get; set; } // hiding base public new string GrossAmount { get; set; } 

从提供的代码中扣除您应该有B:A

你可以隐藏一个方法,以防你想要创建自己的基类的(比方法)实现,这个方法不能被覆盖,因为它不是virtual

在我的经验中,我主要使用隐藏来进行debug

例如,当我不知道是谁设置了某些第3个prt component的属性时,我无法使用哪些代码。 所以我做的是:

  • 从组件创建子类
  • 使用new关键字隐藏感兴趣的属性
  • 将断点置于set
  • 并等待它会被击中。

有时,非常有用并帮助我快速获取信息,尤其是在您学习新componentsframeworkslibraries等等的第一阶段。

通过隐藏方法或属性,您只需说明当您拥有该类型的对象时,您希望停止此类方法的多态。 另外,隐藏方法以非多态方式调用,因此在编译时必须知道调用这些方法类型,因为它只是一个非虚拟方法。

  public class BaseClass { public void PrintMethod() { Console.WriteLine("Calling base class method"); } } public class ChildClass { public new void PrintMethod() { Console.WriteLine("Calling the child or derived class method"); } } class Program { static void Main() { BaseClass bc = new ChildClass(); bc.PrintMethod(); } } 

方法隐藏是指Base Class引用变量指向子类对象时。 它将调用基类中的隐藏方法。

当我们在基类中声明虚方法时。 我们在derived类或子类中重写该方法。 然后Base Class引用变量将调用派生类方法。 这称为方法覆盖。

 class Base { int a; public void Addition() { Console.WriteLine("Addition Base"); } public virtual void Multiply() { Console.WriteLine("Multiply Base"); } public void Divide() { Console.WriteLine("Divide Base"); } } class Child : Base { new public void Addition() { Console.WriteLine("Addition Child"); } public override void Multiply() { Console.WriteLine("Multiply Child"); } new public void Divide() { Console.WriteLine("Divide Child"); } } class Program { static void Main(string[] args) { Child c = new Child(); c.Addition(); c.Multiply(); c.Divide(); Base b = new Child(); b.Addition(); b.Multiply(); b.Divide(); b = new Base(); b.Addition(); b.Multiply(); b.Divide(); } } 

输出: –

加法儿童

乘以儿童

划分孩子

加法基础

乘以儿童

划分基数

加法基础

乘以基数

划分基数

在重写时,编译器会检查类的对象,但在隐藏编译器时只检查类的引用