简体   繁体   English

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

[英]Exact difference between overriding and hiding

Can anybody tell the working of overriding and hiding in terms of memory and references. 任何人都可以用内存和引用来讲述覆盖和隐藏的工作。

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

Here memory is with class B but in the second statement aa.Test2 class A's method will be called. 这里的内存属于类B,但是在第二条语句aa.Test2中,将调用类A的方法。 Why is it? 为什么? If B has memory then B's method should be called (in my point of view). 如果B有内存,那么应该调用B的方法(以我的观点)。

Any link / exercise that describes this fundamental very deeply and completely will be a big help. 任何非常深刻,完整地描述这一基础的链接/练习都将有很大帮助。

Take a look at this answer to a different question by Eric Lippert. 看看埃里克·利珀特(Eric Lippert) 对另一个问题回答

To paraphrase (to the limits of my comprehension), these methods go into "slots". 为了解释(在我的理解范围内),这些方法进入了“插槽”。 A has two slots: one for Test1 and one for Test2 . A有两个插槽:一个用于Test1 ,一个用于Test2

Since A.Test1 is marked as virtual and B.Test1 is marked as override , B 's implementation of Test1 does not create its own slot but overwrites A 's implementation. 由于A.Test1被标记为virtualB.Test1被标记为override ,因此BTest1实现不会创建自己的插槽,而是会覆盖A的实现。 Whether you treat an instance of B as a B or cast it to an A , the same implementation is in that slot, so you always get the result of B.Test1 . 无论您将B的实例视为B还是将其B.Test1转换为A ,该插槽中都具有相同的实现,因此您始终可以获得B.Test1的结果。

By contrast, since B.Test2 is marked new , it creates its own new slot. 相比之下,由于B.Test2被标记为new ,因此它将创建自己的插槽。 (As it would if it wasn't marked new but was given a different name.) A 's implementation of Test2 is still "there" in its own slot; (因为它会如果没有被标记为new 。但被赋予了不同的名称) A的执行Test2仍然是‘有’,在自己的插槽; it's been hidden rather than overwritten. 它被隐藏而不是被覆盖。 If you treat an instance of B as a B , you get B.Test2 ; 如果将B的实例视为B ,则得到B.Test2 if you cast it to an A , you can't see the new slot, and A.Test2 gets called. 如果将其A.Test2转换为A ,则看不到新的插槽,并A.Test2

To add to @Rawling's answer , practical examples could be shown using an example such as this: 为了增加@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. Overriding 1.覆写

In case of the overriden property, base class' virtual method's slot is replaced by a different implementation. 如果使用了重写属性,则基类的虚拟方法的插槽被其他实现替换 Compiler sees the method as virtual , and must resolve its implementation during run-time using the object's virtual table. 编译器将方法视为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. Hiding 2.隐藏

When a method or a property is hidden using the new keyword, the compiler creates a new non-virtual method for the derived class only; 当使用new关键字隐藏方法或属性时,编译器将仅为派生类创建一个新的非虚拟方法。 base class' method remains untouched. 基类的方法保持不变。

If the type of the variable is Base (ie only contains the virtual method), its implementation will be resolved through the vtable. 如果变量的类型为Base (即仅包含虚拟方法),则将通过vtable解析其实现。 If the type of the variable is New , then the non-virtual method or property will be invoked. 如果变量的类型为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. Summary 3.总结

If a part of your code accepts the base type, it will always use the virtual table during run-time. 如果您的代码的一部分接受基本类型,则它将在运行时始终使用虚拟表。 For most OOP scenarios, this means that marking a method as new is very similar to giving it a completely different name. 对于大多数OOP场景,这意味着将方法标记为new方法与为其赋予完全不同的名称非常相似。

4. Object sizes after instantiation 4.实例化后的对象大小

Note that instantiating any of these types doesn't create a copy of the virtual table. 请注意, 实例化这些类型中的任何一种都不会创建虚拟表的副本。 Each .NET object has a couple of bytes of header and a pointer to the virtual table of table of its type ( class ). 每个.NET对象都有几个头字节和一个指向其类型( class )表的虚拟表的指针。

Regarding the new property (the one which is not virtual), it is basically compiled as a static method with thiscall semantics, meaning that it also doesn't add anything to the size of the instance in memory. 关于new属性(非虚拟属性),基本上将其编译为具有this调用语义的静态方法,这意味着它也不会在内存中增加任何实例大小。

Already answered at here 已经在这里回答

Overriding is the definition of multiple possible implementations of the same method signature, such that the implementation is determined by the runtime type of the zeroth argument (generally identified by the name this in C#). 覆盖是对同一方法签名的多个可能实现的定义,这样,实现由第零个参数的运行时类型确定(通常在C#中由名称this标识)。

Hiding is the definition of a method in a derived type with a signature identical to that in one of its base types without overriding. 隐藏是对派生类型中方法的定义,该方法的签名与其基本类型之一相同,而没有覆盖。

The practical difference between overriding and hiding is as follows: 覆盖和隐藏之间实际区别如下:

Hiding is for all other members (static methods , instance members, static members). 隐藏适用于所有其他成员(静态方法,实例成员,静态成员)。 It is based on the early binding . 它基于早期绑定。 More clearly , the method or member to be called or used is decided during compile time. 更明确地说,要在编译时确定要调用或使用的方法或成员。

•If a method is overridden, the implementation to call is based on the run-time type of the argument this. •如果某个方法被覆盖,则要调用的实现将基于参数this的运行时类型。 •If a method is simply hidden, the implementation to call is based on the compile-time type of the argument this. •如果仅隐藏方法,则要调用的实现基于参数this的编译时类型。

Here are some samples : Example # 1 . 以下是一些示例: 示例1 and Example # 2 示例#2

Test1() method in class A and test1() method in class B will executes according to MethdOverriding . A类的Test1()方法和B类的test1()方法将根据MethdOverriding执行。

Test2() method in class A and test2() method in class B will executes according to Method Hiding . A类的Test2()方法和B类的test2()方法将根据Method Hiding执行。

In method Overriding the child class members will execute, and in Method Hiding the Parent class members will execute. 重写方法中,将执行子类成员,而在隐藏方法中 ,将执行父类成员。

Deducting from the code provided you should have B:A . 从提供的代码中扣除,您应该拥有B:A

You can hide a method in case when you want create your own implementation of the (say) method of the base class, which can not be overriden, cause, say, it's not virtual . 如果想要创建自己的基类的(say)方法的实现,则可以隐藏该方法,该方法不能被覆盖,导致它不是virtual

In my expirience, I used hiding mostly for debug purposes. 根据我的经验,我主要是为了进行debug隐藏

For example when I don't know who sets the property of some 3rd prt component , whom code is not available to me. 例如,当我不知道是谁设置了第三个prt component的属性时,谁的代码对我不可用。 So what I do is: 所以我要做的是:

  • create a child class from the component 从组件创建一个子类
  • hide the property of interest with new keyword new关键字隐藏感兴趣的属性
  • put the breakpoint in set set断点
  • and wait when it will be hit. 等待它被击中。

Sometimes, very useful and helps me get information in fast way, especially in first stage when you're learning new components , frameworks , libraries .. whatever. 有时,这非常有用,可以帮助我快速获取信息,尤其是在学习新componentsframeworkslibraries第一阶段。

Put simply when overriding a method or property the override method must have the same signature as the base method. 简单地说,覆盖方法或属性时,覆盖方法必须具有与基本方法相同的签名。 When hiding this is not required, the new object can take any form as shown below 当不需要隐藏它时,新对象可以采用任何形式,如下所示

// base
    public int GrossAmount { get; set; }

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

By hiding a method or a property you are simply stating that you want to stop such method being polymorphic when you have an object of that type. 通过隐藏方法或属性,您只是在说要在具有该类型的对象时停止这种方法是多态的。 Additionally hidden methods are called in a non polymorphic way so to call these method type has to be know at compile time, as it was a simply non virtual method. 另外,以非多态方式调用隐藏方法,因此在编译时必须知道调用这些方法的类型,因为这是一个简单的非虚拟方法。

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

Method Hiding is that when Base Class reference variable pointing to a child class object. 方法隐藏是当基类引用变量指向子类对象时。 It will invoke the hidden method in base Class. 它将在基类中调用隐藏的方法。

Where as, When We declare virtual method in the base class. 当我们在基类中声明虚拟方法时。 We override that method in the derived or child class. 我们在派生类或子类中重写该方法。 Then Base Class reference variable will call the derived class method. 然后,基类引用变量将调用派生的类方法。 This is called Method Overriding. 这称为方法重写。

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

Output : - 输出:-

Addition Child 加法儿童

Multiply Child 乘子

Divide Child 划分孩子

Addition Base 加法基础

Multiply Child 乘子

Divide Base 分基

Addition Base 加法基础

Multiply Base 乘以基数

Divide Base 分基

At the time of overriding the compiler checks the object of the class but in in hiding compiler only checks the reference of the class 在覆盖时,编译器检查类的对象,但是在隐藏时,编译器仅检查类的引用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM