C#复杂继承

C# complex inheritance

假设我们有这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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();

现在的问题是什么是C.P和IC.P?实际上我知道是1和2,但你能解释一下为什么吗?


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

I ic = new C();的情况下,它很高兴地调用P的直接接口实现,因为它与多态虚拟调用无关,因此在这种情况下它调用C.P

注:这里的关键是,C在其继承声明中(即,看起来像class C : B, I而不是class C : B中)直接包含I。如果没有,那么ic.P调用将再次引用被重写的继承P,就像C.P一样,并返回1。

您应该看到一个警告,上面写着以下内容,这有助于提示您有些事情做得不太正确:

'C.P' hides inherited member 'B.P'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.


class B : A表示B类继承了A类,简单地说,B类将具有A类所具有的所有属性函数。但是,当你说public override int P时,"关键字"是override),意味着对于"p"类,b将以不同的方式表现。就像"隐藏"了"P"的A级。

更有用的是阅读文档:

继承


应该是2和2。

它是1和2,因为您没有在C中正确地实现P。它将p隐藏在b.c中,应该是:

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

这里需要关键字override,如果绝对需要这样做(要使1 ans 2作为对象状态),则需要使用new关键字:

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

如果您使用的是Visual Studio,您应该看到一个警告。


让我们分析每一个:

1
A c = new C();

AP实现为virtual方法。子类需要声明P,添加override修饰符,以便实际覆盖它(msdn引用):

The override modifier is required to extend or modify the abstract or virtual implementation of an inherited method, property, indexer, or event.

现在第二个:

1
I ic = new C();

接口I没有(显然)实现方法P,也没有将其声明为virtual(虽然它隐式定义为virtual sealed,这意味着实现了后期绑定到ic的实例(早期绑定到接口I)。将被使用。


这一页与你的文章非常相关。在这种情况下,会发生什么取决于被视为当前类型的内容。因此,对于CP是1,因为它使用了A中的P方法,而B覆盖了该方法。它调用子链中最远的方法,该方法仍然是A的方法。对于ic,再次调用子链最远的方法,这次在C调用,因为它是I中存在的方法的有效实现。这在第一种情况下不会发生,因为A.P不被C.P覆盖。