2013-05-19 68 views
4

假设我们有这样的代码:C#复杂的继承

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,但你能解释我为什么吗?

+0

可能重复[继承与C#中的接口](http://stackoverflow.com/questions/6188827/inheritance-vs-interface-in-c-sharp) – paulsm4

+0

@ paulsm4我不认为它是重复的。 – gsharp

回答

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.

你应该会看到一个警告,下面写着,这有助于给你一个线索的东西ISN” t做得很对:

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

+1

我认为这个答案很好,但仍然错过了一些东西。问题也是关于哪个方法被“映射”为接口的实现。这里非常重要的一点是'C'类在声明'class C:B,I'中提到接口'I'_again_。因为如果没有“I”的这种“重复”,类型'C'仍然会执行'I',因为继承自'A'。但如果我们在那里没有提到'I',只是'C类:B',结果会有所不同。我建议提问者阅读_C#Language Specification_中的*** Interface re-implementation ***部分。 –

+0

@JeppeStigNielsen好点,我应该更明确地提到这一点。我引用了C对我的直接实现,但是在重读之后,我可以看到读者如何忽略这一点。我会更新。 – Gjeltema

2

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

更有用的是阅读文档:

Inheritance

0

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

0

我们来分析一下每个:

A c = new C(); 

A工具P作为virtual方法。子类需要声明P以便实际覆盖它(MSDN reference)将override改性剂:

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

现在第二:

I ic = new C(); 

接口I不(显着)实现方法P,既不声明为virtual(尽管它隐含定义为virtual sealed),这意味着的实施将使用迟于ic(早期绑定到接口I)的实例。

0

它应该是2和2.

它是1和2,因为您尚未在C中正确实施P。它隐藏p在B. C应该:

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

关键字override这里需要,如果你确实需要使用这种方式(有1个ANS 2作为对象状态),则需要使用new关键字:

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

而且,如果您使用的是Visual Studio,则应该已经看到此警告。