【问题标题】:Polymorphism/Overriding多态性/覆盖
【发布时间】:2012-02-08 08:07:17
【问题描述】:

有人能解释一下这两个例子有什么区别吗?

A 类

protected virtual string GetData()

B类

private override string GetData()

还有以下内容:

A 类

protected string GetData()

B类

private string GetData()

假设“B 类”继承自“A 类”。

我一直认为如果你想覆盖一个方法,你需要在超类中使用virtual,在子类中使用override,但是我尝试删除关键字并且程序编译得很好。如果有的话,具体有什么区别?

【问题讨论】:

  • 你看到 B.GetData() 下的波浪线了吗?您是否在查看 + 错误列表中看到警告?不容错过,当您知道自己在做什么时,请使用 new 关键字。
  • 在第一个例子中 B 的方法不能是私有的。它不会编译。

标签: c# .net oop inheritance polymorphism


【解决方案1】:

您展示的第二个示例隐藏了父级的 GetData,它不会覆盖它。

例子:

private class Base
{
    public virtual void Test()
    {
        Console.WriteLine("Base");
    }

    public void Test2()
    {
        Console.WriteLine("Base");
    }
}

private class Derived : Base
{
    public override void Test()
    {
        Console.WriteLine("Derived");
    }

    public void Test2()
    {
        Console.WriteLine("Derived");
    }
}

static void Main()
{
    Base b = new Base();
    Derived d = new Derived();
    Base dInB = new Derived();

    b.Test();
    d.Test();
    dInB.Test();

    b.Test2();
    d.Test2();
    dInB.Test2();

    Console.ReadKey(true);
}

它输出:

Base    // Base.Test()
Derived // Derived.Test()
Derived // Derived.Test()
Base    // Base.Test2()
Derived // Derived.Test2()
Base    // You think you're calling Derived.Test2(), but you actually call Base.Test2()

实际上这个示例是无效的,因为它应该在派生类的public new void Test2() 中使用new 关键字。

它就像运算符重载一样工作。它实际上并没有覆盖任何东西。当您拥有确切的类型 Derived 时,它会调用新方法。

你必须非常小心隐藏成员,它根本不像覆盖(类)或实现(接口)。只有当你拥有 exact 类型时,它才会调用new 方法,否则它仍然会调用基类型的方法!

【讨论】:

    【解决方案2】:

    不同之处在于,在第一种情况下,您是覆盖,而在第二种情况下,您是在隐藏,这是完全不同的。

    第一种情况:

    class B: A
    {
        void Foo()
        {
            B b = new B();
            A a = b;
    
            a.GetData() //B's GetData() will be called
            b.GetData() //B's GetData() will be called
        }
    }
    

    另一方面,在第二种情况下:

    class B: A
    {
        void Foo()
        {
            B b = new B();
            A a = b;
    
            a.GetData() //A's GetData() will be called
            b.GetData() //B's GetData() will be called
        }
    }
    

    在第二种情况下,您只是隐藏了 A 的 GetData() 实现,但您始终能够通过类型为 A 的变量调用 A 的实现,即使该变量引用类型 B 的实例。请注意,这是完全不同的从覆盖的行为方式。

    【讨论】:

    • 感谢您的解释!
    【解决方案3】:
    public class A
    {
        public virtual string GetData() { return "A";}
    }
    
    public class B : A
    {
        public override string GetData() { return "B"; }
    }
    

    如果您使用以下代码块中的类,您期望什么?

            A a = new A();
            B b = new B();
            A c = new B();
    
            Console.WriteLine(a.GetData());
            Console.WriteLine(b.GetData());
            Console.WriteLine(c.GetData());
    

    这将打印“A”“B”“B”。变量 c 存储为 A 类型,但在执行该方法时,代码被解析为“真实”实现。 (虚函数表及解析原理见google)

    如果您不使用下面代码中的 virtual 和 override,这将打印“A”“B”“A”。

    public class A
    {
        public string GetData() { return "A";}
    }
    
    public class B : A
    {
        public new string GetData() { return "B"; }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-06-26
      • 2012-10-11
      • 1970-01-01
      • 1970-01-01
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      • 2019-07-11
      相关资源
      最近更新 更多