方法是默认的“虚拟”还是“非虚拟”?:

时间:2013-03-17 19:05:52

标签: c# oop

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

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

此测试示例似乎向我建议默认情况下方法和虚拟,并且在LastName属性的情况下,隐含“overrrides”,但我很确定这不是案子。

我错过了什么?

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 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分: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#编程面试问题:)

答案 2 :(得分:2)

对多态性的充分理解将清除这一点:

Polymorphism (C# Programming Guide)

用新成员隐藏基类成员


如果希望派生成员与基类中的成员具有相同的名称,但您不希望它参与虚拟调用,则可以使用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关键字放在override关键字之前。以下代码提供了一个示例:

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实现。

答案 3 :(得分:0)

好吧,你做对了。如果它不是虚拟的,则会被隐藏。

new关键字在继承层次结构链中制动虚拟覆盖。

阅读简单示例: Polymorphism, Method Hiding and Overriding in C#