派生的基类方法,是通过基类实例还是派生类实例调用的?

时间:2017-03-19 09:21:52

标签: c# inheritance

派生类可以访问基类方法,所以当在派生类实例上调用基类方法时,它实际上是使用派生类实例还是在幕后使用基类实例,因为我们知道派生类是初始化,它也初衷了它的基础。

考虑下面的例子,虽然它是虚拟/新的一部分,但是当看到这个问题时会想到这个问题。

 class Car
{
    public void DescribeCar()
    {
        System.Console.WriteLine("Four wheels and an engine.");
        ShowDetails();
    }

    public virtual void ShowDetails()
    {
        System.Console.WriteLine("Standard transportation.");
    }
}

class ConvertibleCar : Car
{
    public new void ShowDetails()
    {
        System.Console.WriteLine("A roof that opens up.");
    }
}

ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();

所以当我们这样做时,基类" ShowDetails()"即使实例是派生类,也会调用它。

所以在幕后,它是否使用基类实例。当我们"覆盖" ConvertibeCar showdetails即覆盖派生类方法然后它调用派生类" showdetails()"

2 个答案:

答案 0 :(得分:0)

子类中重写方法的重点在于子类的方法将在运行时执行,即使编译时类型是超类的类型。

如果由于某种原因需要超类的实例,则应该向超类添加一个复制构造函数并使用它来创建这样的实例:

public class Base {
    ...
    ...
    Base (Base source) {
        // copy the properties
    }
}

然后:

public void makeStr(Derived d){ 
    Base b = new Base(d);
    ... 
    b.getStr() will call the Base class implementation
}

答案 1 :(得分:-1)

如果我们检查为主程序生成的IL,看起来它使用Car实例进行调用:

C#代码:

class ConvertibleCar : Car
{

}

和IL:

IL_0000:  nop         
IL_0001:  newobj      UserQuery+ConvertibleCar..ctor
IL_0006:  stloc.0     // car
IL_0007:  ldloc.0     // car
IL_0008:  callvirt    UserQuery+Car.ShowDetails
IL_000D:  nop         
IL_000E:  ret    

当我们在ShowDetails中实现ConvertibleCar时,它正在使用这个类实例:

class ConvertibleCar : Car
{
    public new void ShowDetails()
    {
        System.Console.WriteLine("A roof that opens up.");
    }
}

然后生成的IL看起来像:

IL_0000:  nop         
IL_0001:  newobj      UserQuery+ConvertibleCar..ctor
IL_0006:  stloc.0     // car
IL_0007:  ldloc.0     // car
IL_0008:  callvirt    UserQuery+ConvertibleCar.ShowDetails
IL_000D:  nop         
IL_000E:  ret   

是的,我从IL生成器中清除了ConvertibleCar的构造函数,Car构造函数也被称为:

ConvertibleCar..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        UserQuery+Car..ctor
IL_0006:  ret