4

假设我们有这样的代码:

interface I
{
    int P { get; }
}

class A : I
{
    public virtual int P { get { return 0; } }
}

class B : A
{
    public override int P { get { return 1; } }
}

class C : B, I
{
    public int P { get { return 2; } }
}

A c = new C();
I ic = new C();

现在的问题是 cP 和 ic.P 应该是什么?实际上我知道它会是 1 和 2,但你能解释一下为什么吗?

4

5 回答 5

18

在 的情况下A c = new C();,它将调用它找到的第一个正确覆盖在 中声明的函数的函数A。由于C.P没有覆盖它,而是隐藏它,所以虚拟树遍历(多态解析)不会调用该C.P函数,而是调用继承树中最低的一个,即B.P.

在 的情况下I ic = new C();,它会很乐意调用 的直接接口实现P,因为它不关心多态虚拟调用,所以在这种情况下它会调用C.P

注意:这里的关键是C直接I在它的继承声明中(即看起来像class C : B, I而不是class C : B)这种行为。如果没有,ic.P调用将再次引用被覆盖的继承P,就像 一样c.P,并且也将返回 1。

您应该会看到一条警告,其中包含以下内容,这有助于为您提供一些线索,表明某些事情做得不太正确:

' C.P' 隐藏继承的成员 ' B.P'。要使当前成员覆盖该实现,请添加override关键字。否则添加new关键字。

于 2013-05-19T18:13:18.783 回答
2

class B : A意味着 B 类继承了 A 类,简单来说意味着 B 类将具有 A 类所具有的所有属性功能。但是当你说public override int P,(“关键词”被覆盖)意味着对于'P'类B将以不同的方式表现。这就像为'P'“隐藏”A类。

更有用的是阅读文档:

遗产

于 2013-05-19T18:12:15.653 回答
0

应该是 2 和 2。

这是 1 和 2,因为您没有在 C 中正确实现 P 。它在 B 中隐藏了 P。C 应该是:

class C : B, I
{
    public override int P { get { return 2; } }
}

这里需要关键字override,如果您绝对需要这种方式(将 1 和 2 作为对象状态),则需要使用new关键字:

class C : B, I
{
    public new int P { get { return 2; } }
}

如果您使用的是 Visual Studio,您应该已经看到了警告。

于 2013-05-19T18:30:19.623 回答
0

让我们逐一分析:

A c = new C();

A实现Pvirtual方法。子类需要声明P添加override修饰符才能实际覆盖它(MSDN 参考):

需要 override 修饰符来扩展或修改继承的方法、属性、索引器或事件的抽象或虚拟实现。

现在是第二个:

I ic = new C();

InterfaceI没有(显然)实现 method P,也没有将其声明为virtual(尽管它被隐式定义为virtual sealed),这意味着将使用后期绑定到ic(早期绑定到 interface I)的实例的实现。

于 2013-05-19T18:15:32.510 回答
0

此页面与您的帖子非常相关。在这种情况下,会发生什么取决于当前类型。因此,对于c,P是 1,因为它使用了Pfrom 的方法A,该方法被B. 它正在调用子链中最远的方法,该方法仍然是A. 对于ic,该方法再次在子链的最下方调用,这次是在C,因为它是 中存在的方法的有效实现I。这在第一种情况下不会发生,因为A.P没有被C.P.

于 2013-05-19T18:13:52.380 回答