假设我们有这样的代码:
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,但你能解释一下为什么吗?
- C中继承与接口的可能重复#
- @我认为这不是复制品。
在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.
号
- 我觉得这个答案很好,但还是有遗漏。问题还在于"映射"哪个方法来实现接口。这里非常重要的是,类C在声明class C : B, I中再次提到接口I。因为如果没有I的这种"重复",由于A的继承,C类型仍将实现I。但是,如果我们只使用class C : B,而没有提到I,结果会有所不同。我建议asker阅读C语言规范中的接口重新实现部分。
- @杰佩斯蒂尼尔森说得对,我应该更明确地提到这一点。我提到了C对I的直接实现,但是在重新阅读之后,我可以看到这可能是读者错过的一点。我会更新的。
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,您应该看到一个警告。
让我们分析每一个:
类A将P实现为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.
号
现在第二个:
号
接口I没有(显然)实现方法P,也没有将其声明为virtual(虽然它隐式定义为virtual sealed,这意味着实现了后期绑定到ic的实例(早期绑定到接口I)。将被使用。
这一页与你的文章非常相关。在这种情况下,会发生什么取决于被视为当前类型的内容。因此,对于C,P是1,因为它使用了A中的P方法,而B覆盖了该方法。它调用子链中最远的方法,该方法仍然是A的方法。对于ic,再次调用子链最远的方法,这次在C调用,因为它是I中存在的方法的有效实现。这在第一种情况下不会发生,因为A.P不被C.P覆盖。