为什么我们将子类对象分配给父类引用变量?

时间:2015-07-28 18:45:52

标签: c#

我有以下代码。

public class Parent
{
    public void Print()
    {
        Console.WriteLine ("Parent Method");
    }
}

public class Child : Parent
{
    public new void Print()
    {
        Console.WriteLine ("Child Method");
    }
}

public class Program
{
    public static void Main()
    {
        Child C = new Child();
        C.Print();
    }
}

如果我运行此代码,我会得到结果" Child Method" 但是,如果我执行以下操作,为什么我会得到结果"父方法"?

public class Parent
{
    public void Print()
    {
        Console.WriteLine ("Parent Method");
    }
}

public class Child : Parent
{
    public new void Print()
    {
        Console.WriteLine ("Child Method");
    }
}

public class Program
{
    public static void Main()
    {
        Parent P = new Child();   // The only difference is this.
        P.Print();
    }
}

唯一的区别如下

Child C = new Child();   
Parent P = new Child();

我认为new Child()意味着我们创建了Child类的实例。 我认为CP都只是对象引用变量,它们保存Child类实例的位置。
如果我错了,你可以纠正我,或者告诉我,如果我错过了什么,因为我不明白为什么在上述情况下我会得到不同的结果?

5 个答案:

答案 0 :(得分:19)

这是因为您已在Print中重新声明了Child方法。因此,在编译时,P.Print()会解析为Parent.Print,但C.Print()会解析为Child.Print()。如果您在Child中使用了重写的虚拟方法,则他们同时打印"子方法":

public class Parent
{
    // Declare this as virtual, allowing it to be overridden in
    // derived classes. The implementation will depend on the
    // execution-time type of the object it's called on.
    public virtual void Print()
    {
        Console.WriteLine ("Parent Method");
    }
}

public class Child : Parent
{
    // Override Parent.Print, so if Print is called on a reference
    // with compile-time type of Parent, but at execution it
    // refers to a Child, this implementation will be executed.
    public override void Print()
    {
        Console.WriteLine ("Child Method");
    }
}

相关:

答案 1 :(得分:9)

这是引擎盖下发生的事情

Child C = new Child();
C.Print();

因为您隐藏了方法,而不是覆盖它们。所以隐藏了Parent中的Print方法,并调用了Child.Print()。

enter image description here

 Parent P = new Child();   // The only difference is this.
 P.Print();

将在父类型参考上调用此(New Child())。

enter image description here

如果你尝试这个,父类型引用将被转换为子类型。从此以后调用Child.Print()。

Parent P = new Child(); 
((Child)P).Print();

enter image description here

输出将是:子方法

答案 2 :(得分:4)

由于Print方法不是virtual,编译器不会发出代码来告诉CLR根据实际的运行时类型调用该方法。

因此,当您的变量被称为Child时,将调用Child.Print。但是,当您将其称为Parent时,将使用Parent.Print

这里使用new关键字仅用于 shadowing ,告诉编译器子方法确实隐藏父方法而不是压倒它,但没有效果。

答案 3 :(得分:1)

JCronin,您正在使用Parent P = new Child()投射到Parent。要获取Child类行为,您必须将其强制转换为Child(var x =(Child)P)或创建Child实例实例(Child P = new Child())。

请参阅Downcasting

答案 4 :(得分:0)

因为您将P的类型声明为Parent。当您为其分配Child时,它将被转换为该类型。