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

本文关键字:区别 之间 隐藏 覆盖 | 更新日期: 2023-09-27 18:37:11

谁能从内存和引用的角度分辨出覆盖和隐藏的工作。

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被标记为overrideBTest1实现不会创建自己的插槽,而是覆盖A的实现。无论您是将B实例视为B还是将其转换为A,该插槽中都有相同的实现,因此您始终会得到B.Test1的结果。

相比之下,由于B.Test2被标记为new,它会创建自己的插槽。(如果它没有被标记为new而是被赋予了不同的名称。 A Test2的实现仍然"存在"在自己的插槽中;它已被隐藏而不是覆盖。如果将B的实例视为B,则会得到B.Test2;如果将其投射到A,则看不到新插槽,并且A.Test2被调用。

为了补充@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. 覆盖

对于重写属性,基类的虚拟方法的插槽将替换为不同的实现。编译器将该方法视为虚拟方法,并且必须在运行时使用对象的虚拟表解析其实现。

{
    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 标识)。

隐藏是派生类型中方法的定义,该方法的签名与其基类型之一中的签名相同,而不重写。

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

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

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

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

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

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

在方法重写中,将执行子类成员

,在"隐藏方法"中,将执行父类成员。

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

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

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

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

在我去世的时候,我主要出于debug目的而使用隐藏

例如,当我不知道谁设置了某个 3rd 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();
        }
       }

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

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

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();
    }
}

输出:-

加法子项

乘以子级

划分子项

加法底座

乘以子级

划分基地

加法底座

乘基数

划分基地

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