16

我正在学习 C#,我遇到了以下问题。我有两个类:基类和派生类:

class MyBase
{
    public void MyMethod()
    {
        Console.WriteLine("MyBase::MyMethod()");
    }
}


class MyDerived: MyBase
{
    public void MyMethod()
    {
        Console.WriteLine("MyDerived::MyMethod()");
    }
}

现在,没有virtualoverride关键字。当我编译这个时,我得到了我试图MyMethodMyBase课堂上隐藏的警告(这当然是预期的)。

我想要做的是从具有派生类实例的基类中调用该方法。我这样做:

MyDerived myDerived = new MyDerived();
((MyBase)myDerived).MyMethod();

当我没有virtual在方法中指定任何 , etc. 关键字时,它可以正常工作。我尝试将关键字组合起来,得到以下结果:

| MyBase::MyMethod | MyDerived::MyMethod | Result printed on the console |
| -----------------|---------------------|-------------------------------|
| -                | -                   | MyBase::MyMethod()            |
| -                | new                 | MyBase::MyMethod()            |
| virtual          | new                 | MyBase::MyMethod()            |
| virtual          | override            | MyDerived::MyMethod()         |

我希望这张表对你来说很清楚。我有两个问题

  1. 从基类()调用函数是否正确((MyBase)myDerived).MyMethod();?我知道base关键字,但只能从派生类内部调用它。这样对吗?
  2. 为什么在最后一种情况下(使用virtualoverride修饰符)调用的方法来自派生类?你能解释一下吗?
4

4 回答 4

19

当您virtual在覆盖该方法的类型的实例上调用方法时,将始终调用被覆盖的版本,即使您强制转换为基类。

在覆盖该方法的类上调用虚方法的基实现的唯一方法是在派生类(而不是基类)中创建第二个方法,该方法使用base关键字调用该方法。

一般来说,需要这样做是一个糟糕的 API 设计的标志——如果你认为你需要调用基本版本,那么派生版本可能应该有一个不同的名称。

于 2010-03-23T12:38:20.343 回答
3

你是对的 -base只能从派生类 - Source中调用。

此页面还提供了如何覆盖基类定义的示例。

于 2010-03-23T12:40:44.980 回答
3

至于你的第二个问题,你并没有改变你引用的对象的类型,只是你引用它的接口。因此,如果您有一个从 A 继承并覆盖函数 C 的对象 B,即使您将 B 称为 A,它仍然会调用最派生类型的实现,在这种情况下是 B。

于 2010-03-23T12:42:14.003 回答
2
  1. 没错,base是指给定实例的基类。
  2. 所涉及的机制称为多态性:您应该更好地工作而无需警告。自然面向对象的好方法是您提到的最后一个案例。

顺便说一句,尽量避免编写强制替换原则的代码,换句话说,不要编写依赖于类层次结构实现的代码,因为如果您将新的派生类添加到你的基类。

于 2010-03-23T12:44:39.143 回答