根据类似的StackOverflow问题和其他文章,c#方法在默认情况下是"非虚拟的",我认为这意味着您不能在派生类中重写它们。
如果这是真的,你能向我解释一下,在下面的例子中,我如何能够在继承基类的子类中实现属性LastName,而在基类中不将属性标记为"虚拟"?孩子。LastName属性"隐藏"(VB"阴影")在基类相同的属性?如果是这样,为什么在Child中没有使用"new"关键字。LastName属性来表示这个?
这个测试示例似乎向我暗示,默认情况下方法和是虚拟的,在LastName属性的情况下,隐含了"overrides",但我很确定情况并非如此。
我错过了什么?
public class BaseClass
{
private string _FirstName;
public virtual string FirstName {
get { return _FirstName; }
set { _FirstName = value; }
}
private string _LastName;
public string LastName {
get { return _LastName; }
set { _LastName = value; }
}
public void Go()
{
MessageBox.Show("Going at default speed in Base Class");
}
public void Go(int speed)
{
MessageBox.Show("Going at " + speed.ToString() + " in Base Class");
}
}
public class Child : BaseClass
{
public override string FirstName {
get { return "Childs First Name"; }
set { base.FirstName = value; }
}
public string LastName {
get { return "Child's Last Name"; }
set { base.LastName = value; }
}
public void Go()
{
MessageBox.Show("Going in Child Class");
}
public void Go(int speed)
{
MessageBox.Show("Going at " + speed.ToString() + " in Child Class");
}
}
方法在c#中默认不是虚拟的。子类中的LastName隐藏了BaseClass的LastName。据我所知,这段代码甚至可以编译,但是编译器会提供警告,告诉应该使用new关键字。
默认为非虚拟。
子类隐藏了基的LastName
属性。
如果你写:
BaseClass b = new Child(...);
Console.WriteLine(b.LastName);
您将看到基本实现被调用。
当你编译上面的代码时,编译器会警告你。标准做法是将隐藏基的成员标记为new
。
public new string LastName {
get { return "Child's Last Name"; }
set { base.LastName = value; }
}
这是一个非常常见的c#编程面试问题:)
对多态性的良好理解将澄清这一点:
多态性(c#编程指南)
隐藏带有新成员的基类成员
如果您希望派生成员与基类中的成员具有相同的名称,但不希望它参与虚拟调用,则可以使用new关键字。new关键字放在被替换的类成员的返回类型之前。下面的代码提供了一个示例:
public class BaseClass
{
public void DoWork() { WorkField++; }
public int WorkField;
public int WorkProperty
{
get { return 0; }
}
}
public class DerivedClass : BaseClass
{
public new void DoWork() { WorkField++; }
public new int WorkField;
public new int WorkProperty
{
get { return 0; }
}
}
通过将派生类的实例强制转换为基类的实例,仍然可以从客户端代码访问隐藏的基类成员。例如:DerivedClass B = new DerivedClass();
B.DoWork(); // Calls the new method.
BaseClass A = (BaseClass)B;
A.DoWork(); // Calls the old method.
防止派生类重写虚成员
无论在虚成员和最初声明它的类之间声明了多少个类,虚成员都无限期地保持虚状态。如果类A声明了一个虚成员,类B派生自A,类C派生自B,则类C继承了虚成员,并且可以选择重写它,而不管类B是否为该成员声明了重写。下面的代码提供了一个示例:
public class A
{
public virtual void DoWork() { }
}
public class B : A
{
public override void DoWork() { }
}
派生类可以通过将重写声明为密封来停止虚拟继承。这需要在类成员声明中将密封关键字放在override关键字之前。下面的代码提供了一个示例:
public class C : B
{
public sealed override void DoWork() { }
}
在前面的例子中,DoWork方法对于任何从C派生出来的类都不再是虚的。对于C的实例来说,它仍然是虚的,即使它们被强制转换为B或a类型。
public class D : C
{
public new void DoWork() { }
}
在这种情况下,如果使用D类型的变量在D上调用DoWork,则调用新的DoWork。如果使用C、B或a类型的变量来访问D的实例,则对DoWork的调用将遵循虚拟继承规则,将这些调用路由到类C上的DoWork实现。
好吧,你说对了。如果它不是虚拟的,它将被隐藏。
new
关键字阻止继承层次链中的虚覆盖。
简单示例: c#中的多态性、方法隐藏和重写