假设我们有这样的代码:
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 :(得分: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'。
更有用的是阅读文档:
答案 2 :(得分:0)
This Page与您的帖子非常相关。在这种情况下,发生的情况取决于被视为当前类型的内容。因此,对于c
,P
为1,因为它使用P
中的A
方法,该方法被B
覆盖。它调用的子方法最远的方法仍然是A
的方法。对于ic
,此方法将再次调用子链中最远的方法,这次是C
,因为它是I
中存在的方法的有效实现。在第一种情况下不会发生这种情况,因为A.P
未覆盖C.P
。
答案 3 :(得分:0)
让我们分析每一个:
A c = new C();
类A
将P
实现为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,那么您应该看到一个警告。