默认情况下"virtual"方法是还是"not virtual"?



根据类似的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#中的多态性、方法隐藏和重写

相关内容

最新更新