【问题标题】:Virtual method called from derived instead of base从派生而不是基调用的虚拟方法
【发布时间】:2013-02-14 23:04:14
【问题描述】:

有人可以向我解释为什么当我将类转换为基类时会调用被覆盖的方法:

    class Base
    {
        public virtual void VirtualMethod()
        {
            Console.WriteLine("Base virtual method");
        }
    }

    sealed class Derived : Base
    {
        public override void VirtualMethod()
        {
            Console.WriteLine("Overriden method");
        }
    }

    static void Main(String[] args)
    {
        Derived d = new Derived();
        ((Base)d).VirtualMethod();
    }

我的意思是这段代码打印:

Overriden method

而不是

Base virtual method

它是运行时还是编译时的未来?

我知道我可以通过调用base.VirtualMethod() 从派生中调用 Base 的虚拟方法,但我可以从外部调用它吗? (比如来自Main 或其他类)

【问题讨论】:

  • 请尝试理解@Jon Skeet 的回答。他是完全正确的。设计原因是数十年的丰富经验和拼命寻找更好的编写代码的方法。 “幕后”/机械原因在某种程度上是无关紧要的,因为所有支持 OOP 的语言和运行时都具有相同的行为(至少在涉及虚拟方法时),并且每种语言和运行时都以不同的方式实现。关于你的第二个问题,请看:stackoverflow.com/questions/437926/…

标签: c# virtual base derived-class


【解决方案1】:

方法实现是根据对象的执行时间类型选择的。这是其中的很大一部分。任何人都可以使用:

public void Foo(Base b)
{
    b.VirtualMethod();
}

...不需要知道或关心执行类型是什么,因为多态会处理它。

我知道我可以通过调用 base.VirtualMethod() 从派生中调用 Base 的虚拟方法,但我可以从外部调用它吗?

不(至少,在非虚拟地调用虚拟方法时并非没有一些可怕的黑客行为),这是封装的有意部分。覆盖实现有效地替换了该对象的原始实现。

【讨论】:

  • +1。请注意,该行为与 C++ 相反,其中来自构造函数的虚拟调用将调用基类的实现。这两种行为都令人困惑,并可能带来令人惊讶的副作用,因此通常不建议从构造函数中调用虚函数。
【解决方案2】:

如果你想访问你不应该使用覆盖的基本实现,你应该使用新的。 Override 覆盖任何父实现,新的“隐藏”父实现,以便您可以通过转换为父对象然后调用方法来访问实现。

internal class Program
{
    private static void Main(string[] args)
    {
        Derived d = new Derived();
        d.VirtualMethod();
        ((Base) d).VirtualMethod();

        Console.ReadLine();
    }

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

    private sealed class Derived : Base
    {
        public new void VirtualMethod()
        {
            Console.WriteLine("Overriden method");
        }
    }
}

这将输出:

重写方法
基本虚方法

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多