4

根据这个类似的 StackOverflow 问题和其他文章,默认情况下 C# 方法是“非虚拟的”,我认为这意味着您不能在派生类中覆盖它们。

如果这是真的,请您向我解释一下,在下面的示例中,我如何能够在继承自 Base 类的 Child 类中实现属性 LastName ,而不会在基类中将该属性标记为“虚拟”?Child.LastName 属性是否“隐藏”(VB“阴影”)基类中的相同属性?如果是这样,为什么 Child.LastName 属性中没有使用“新”关键字来表示这一点?

这个测试示例似乎向我建议默认情况下方法和虚拟,并且在 LastName 属性的情况下,隐含“覆盖”,但我很确定情况并非如此。

我错过了什么?

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");
    }

}
4

4 回答 4

4

默认情况下,方法在 C# 中不是虚拟的。Child 类中的 LastName 对 BaseClass 隐藏了 LastName。据我记得,这段代码甚至可以编译,但是编译器会提供警告,告诉应该使用 new 关键字。

于 2013-03-17T19:09:06.053 回答
3

默认情况下它们是非虚拟的。

子类隐藏了基类的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# 编程面试问题 :)

于 2013-03-17T19:10:02.183 回答
2

对多态性的良好理解将清楚这一点:

多态性(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() { }
}

派生类可以通过将覆盖声明为密封来停止虚拟继承。这需要在类成员声明中将sealed 关键字放在覆盖关键字之前。以下代码提供了一个示例:

public class C : B
{
    public sealed override void DoWork() { }
}

在前面的示例中,DoWork 方法对于任何从 C 派生的类都不再是虚拟的。它对于 C 的实例仍然是虚拟的,即使它们被强制转换为类型 B 或类型 A。密封的方法可以通过使用替换为派生类new 关键字,如以下示例所示:

public class D : C
{
    public new void DoWork() { }
}

在这种情况下,如果使用 D 类型的变量在 D 上调用 DoWork,则调用新的 DoWork。如果使用 C、B 或 A 类型的变量访问 D 的实例,对 DoWork 的调用将遵循虚拟继承规则,将这些调用路由到 C 类上的 DoWork 实现。

于 2013-03-17T19:16:19.263 回答
1

好吧,你没看错。如果它不是虚拟的,它将被隐藏。

关键字在new继承层次链中阻止虚拟覆盖。

阅读的简单示例:C# 中的多态性、方法隐藏和覆盖

于 2013-03-17T19:11:27.547 回答