C#复杂继承

时间:2013-05-19 18:05:25

标签: c# inheritance

假设我们有这样的代码:

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

5 个答案:

答案 0 :(得分: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关键字。

答案 1 :(得分:2)

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

的A类

更有用的是阅读文档:

Inheritance

答案 2 :(得分:0)

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

答案 3 :(得分:0)

让我们分析每一个:

A c = new C();

AP实现为virtual方法。子类需要声明P添加override修饰符才能实际覆盖它(MSDN reference):

  

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

现在是第二个:

I ic = new C();

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

答案 4 :(得分:0)

它应该是2和2。

它是1和2,因为你没有在C中正确实现P.它将P隐藏在B.中应该是:

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,那么您应该看到一个警告。