虚拟和覆盖
Virtual and override
我来自 C++ 的世界,您可能知道那里只有一个用于虚拟方法的关键字,即 virtual
。因此,在 C++ 中,您使用相同的 virtual
关键字在派生 class 中重新定义虚方法(在 C# 中,您使用 override
)。我完全了解多态性以及 "override" 和 new
在 C# 中的工作方式。但是,我没能在书上找到在基础和派生的 classes 中为虚方法创建两个不同的关键字背后是否有一些想法,即 virtual
和 override
对应?还是只是为了清楚起见?
为了清楚起见,我假设。我个人更喜欢在从 parent class 更改行为时覆盖 for。此外,我相信它提供了更清晰的事实,即 C# 不允许多重继承,可以看出,C++ 中的 class 可以继承 Grand Parent 和 Parent class.
这是个好问题。
您使用 override
关键字覆盖虚拟方法,因为您实际上可以在派生 class 中定义第二个 virtual
方法,其签名与基 class是虚方法,也可以重写。
这是来自 MSDN 的实际示例:
using System;
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B: A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C: B
{
new public virtual void F() { Console.WriteLine("C.F"); }
}
class D: C
{
public override void F() { Console.WriteLine("D.F"); }
}
class Test
{
static void Main() {
D d = new D();
A a = d;
B b = d;
C c = d;
a.F();
b.F();
c.F();
d.F();
}
}
产量:
B.F
B.F
D.F
D.F
因为:
the C and D classes contain two virtual methods with the same
signature: The one introduced by A and the one introduced by C. The
method introduced by C hides the method inherited from A. Thus, the
override declaration in D overrides the method introduced by C, and it
is not possible for D to override the method introduced by A.
在 a 2003 interview 中,Anders Hejlsberg(C# 的首席架构师)解释说,决定使用两个不同的关键字主要是为了解决基本组件跨版本更改的版本控制问题。用他自己的话说(强调我的):
I can demonstrate to you a very real world versioning problem, one that indeed we see now from experience with Java. Whenever they ship a new version of the Java class libraries, breakage occurs. Whenever they introduce a new method in a base class, if someone in a derived class had a method of that same name, that method is now an override—except if it has a different return type, it no longer compiles. The problem is that Java, and also C++, does not capture the intent of the programmer with respect to virtual.
When you say "virtual," you can mean one of two things. If you did not inherit a method of the same signature, then this is a new virtual method. That's one meaning. Otherwise it is an override of an inherited method. That's the other meaning.
From a versioning perspective, it is important that the programmer indicate their intent when they declare a method virtual. In C#, for example, you must explicitly indicate which meaning of virtual you intend. To declare a new virtual method, you just mark it virtual
. But to override an existing virtual method, you must say override
.
As a result, C# doesn't have the particular versioning problem I described earlier in which we introduce a method in a base class that you already have in a derived class. In your class, you would have declared foo
virtual. Now we introduce a new virtual foo
. Well, that's fine. Now there are two virtual foo
s. There are two VTBL slots. The derived foo
hides the base foo
, but that's fine. The base foo
wasn't even there when the derived foo
was written, so it's not like there's anything wrong with hiding this new functionality. And things continue to work the way they're supposed to.
因此,您正在扩展 class。您将虚拟方法添加到 class。在以后的版本中,基础 class 添加了一个它自己的虚方法,并且它的签名与你的虚方法的签名相匹配。这可能完全是偶然发生的,也可能是因为您的方法恰好实际服务于相关目的(并且您只是在基础 class 设计师之前解决了特定需求)。反正情况是暧昧的。
由于存在两个不同的关键字(virtual
和 override
),C# 编译器可以为您提供不间断的行为(通过隐藏继承的虚方法并将其与您的方法分开virtual 方法)并通过以下警告提请您注意该问题:
'Derived.Foo()' hides inherited member 'Base.Foo()'. To make the current member override that implementation, add the override
keyword. Otherwise add the new
keyword.
现在要求您通过明确意图来解决问题:从现在开始,您是否要覆盖已添加的继承方法(override
)?还是您仍在启动自己的虚拟方法,该方法现在隐藏了继承的方法(virtual
和 new
)?
我来自 C++ 的世界,您可能知道那里只有一个用于虚拟方法的关键字,即 virtual
。因此,在 C++ 中,您使用相同的 virtual
关键字在派生 class 中重新定义虚方法(在 C# 中,您使用 override
)。我完全了解多态性以及 "override" 和 new
在 C# 中的工作方式。但是,我没能在书上找到在基础和派生的 classes 中为虚方法创建两个不同的关键字背后是否有一些想法,即 virtual
和 override
对应?还是只是为了清楚起见?
为了清楚起见,我假设。我个人更喜欢在从 parent class 更改行为时覆盖 for。此外,我相信它提供了更清晰的事实,即 C# 不允许多重继承,可以看出,C++ 中的 class 可以继承 Grand Parent 和 Parent class.
这是个好问题。
您使用 override
关键字覆盖虚拟方法,因为您实际上可以在派生 class 中定义第二个 virtual
方法,其签名与基 class是虚方法,也可以重写。
这是来自 MSDN 的实际示例:
using System;
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B: A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C: B
{
new public virtual void F() { Console.WriteLine("C.F"); }
}
class D: C
{
public override void F() { Console.WriteLine("D.F"); }
}
class Test
{
static void Main() {
D d = new D();
A a = d;
B b = d;
C c = d;
a.F();
b.F();
c.F();
d.F();
}
}
产量:
B.F
B.F
D.F
D.F
因为:
the C and D classes contain two virtual methods with the same signature: The one introduced by A and the one introduced by C. The method introduced by C hides the method inherited from A. Thus, the override declaration in D overrides the method introduced by C, and it is not possible for D to override the method introduced by A.
在 a 2003 interview 中,Anders Hejlsberg(C# 的首席架构师)解释说,决定使用两个不同的关键字主要是为了解决基本组件跨版本更改的版本控制问题。用他自己的话说(强调我的):
I can demonstrate to you a very real world versioning problem, one that indeed we see now from experience with Java. Whenever they ship a new version of the Java class libraries, breakage occurs. Whenever they introduce a new method in a base class, if someone in a derived class had a method of that same name, that method is now an override—except if it has a different return type, it no longer compiles. The problem is that Java, and also C++, does not capture the intent of the programmer with respect to virtual.
When you say "virtual," you can mean one of two things. If you did not inherit a method of the same signature, then this is a new virtual method. That's one meaning. Otherwise it is an override of an inherited method. That's the other meaning.
From a versioning perspective, it is important that the programmer indicate their intent when they declare a method virtual. In C#, for example, you must explicitly indicate which meaning of virtual you intend. To declare a new virtual method, you just mark it
virtual
. But to override an existing virtual method, you must sayoverride
.As a result, C# doesn't have the particular versioning problem I described earlier in which we introduce a method in a base class that you already have in a derived class. In your class, you would have declared
foo
virtual. Now we introduce a new virtualfoo
. Well, that's fine. Now there are two virtualfoo
s. There are two VTBL slots. The derivedfoo
hides the basefoo
, but that's fine. The basefoo
wasn't even there when the derivedfoo
was written, so it's not like there's anything wrong with hiding this new functionality. And things continue to work the way they're supposed to.
因此,您正在扩展 class。您将虚拟方法添加到 class。在以后的版本中,基础 class 添加了一个它自己的虚方法,并且它的签名与你的虚方法的签名相匹配。这可能完全是偶然发生的,也可能是因为您的方法恰好实际服务于相关目的(并且您只是在基础 class 设计师之前解决了特定需求)。反正情况是暧昧的。
由于存在两个不同的关键字(virtual
和 override
),C# 编译器可以为您提供不间断的行为(通过隐藏继承的虚方法并将其与您的方法分开virtual 方法)并通过以下警告提请您注意该问题:
'Derived.Foo()' hides inherited member 'Base.Foo()'. To make the current member override that implementation, add the
override
keyword. Otherwise add thenew
keyword.
现在要求您通过明确意图来解决问题:从现在开始,您是否要覆盖已添加的继承方法(override
)?还是您仍在启动自己的虚拟方法,该方法现在隐藏了继承的方法(virtual
和 new
)?