【问题标题】:Inherited method has no access to new implementation in derived class继承的方法无法访问派生类中的新实现
【发布时间】:2015-05-29 11:50:15
【问题描述】:

正如MSDN article中所引用的:

派生类的类型对象无法访问从基类继承的重新定义的新方法,并且从ShowDetails()继承的方法DescribeCar()中对派生类对象的调用DescribeCar()对@987654324进行@基类的方法。

如果DescribeCar()方法对ConvertibleCar类也可用,怎么就看不到所谓的new ShowDetails()方法呢?

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

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

// Define the derived classes.

// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails
// hides the base class method.
class ConvertibleCar : Car
{
    public new void ShowDetails()
    {
        System.Console.WriteLine("A roof that opens up.");
    }
}


class Program
{

    static void Main(string[] args)
    {
        ConvertibleCar car2 = new ConvertibleCar();
        car2.DescribeCar();
    }
}

//output
// Four wheels and an engine.
// Standard transportation.

【问题讨论】:

  • 真的不清楚你在问什么。 Car.DescribeCar 只“知道”Car.ShowDetails... 这可能在ConvertibleCar 中被覆盖,但这不是代码的作用。相反,它声明了一个新方法...
  • 因为你说它是new,即它不是override,而是隐藏了其他实现。
  • new 和 override 的区别在于,定义为 new 的方法在对象被视为超类时不会被调用,而 override 会。
  • 我要问的是关于 ConvertibleCar.DescribeCar()
  • DescribeCar 在 Car 中定义,无法“看到”您的“新”方法。坦率地说,你几乎不想在方法上使用 new 关键字。

标签: c# inheritance methods method-hiding


【解决方案1】:

new 隐藏旧方法,这意味着如果您直接ConvertibleCar实例上调用它,您将获得派生类行为,但它不会被称为多态

当基类调用它时,它调用的是虚方法,因为它没有被覆盖,所以调用了基类方法。而不是使用方法隐藏(你几乎从不使用),只需覆盖它:

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

【讨论】:

  • “这意味着如果你直接在一个 ConvertibleCar 实例上调用它,你将得到派生类的行为”——你能详细说明一下吗?看起来他/她 正在 通过 car2.DescribeCar(); 在 ConvertibleCar 实例上直接调用它
  • @roryap 我一定会尝试的。诀窍是他没有直接在ConvertibleCar 实例上调用它,他调用的是调用虚拟方法的继承基类方法(因此不知道隐藏方法在派生类)
  • 啊,我刚刚看到我的困惑来自哪里。我混淆了DescribeCarShowDetails。出于某种原因,我认为他正在调用car2.ShowDetails(),这显然会调用派生类方法。
  • @BradleyDotNET “当基类调用它时,它正在调用虚方法”,为什么会这样?我从可用于 ConvertibleCar 类的 DescribeCar 中调用它,但它看不到新方法?
  • @user3723486 因为 ConvertibleCar 没有定义自己的 DescribeCar 方法。
【解决方案2】:

好吧,当您考虑它时 - 想想 没有 继承 - 这就像问为什么 Car.DescribeCar 无法访问 ConvertibleCar.ShowDetails

ConvertibleCar.ShowDetails 本质上是一个不是Car 成员的方法,如果你愿意的话——因为new 关键字。 Car 但是有一个方法 ShowDetails

Car.DescribeCar 作为Car 的成员方法,具有Car.ShowDetails 而不是ConvertibleCar.ShowDetails 的可见性,因此Car.ShowDetails 是被调用的对象。

也许这会更清楚。使用new 关键字,这是另一种思考方式:

class Car
{
  ...
  public virtual void ShowDetails(){..}
}

class ConvertibleCar : Car
{
  public void new_ShowDetails(){}
}

Car 不知道ConvertibleCar.new_ShowDetails,因此无法调用该方法。

【讨论】:

  • 你甚至可以推导出来,你的例子是准确的:)
【解决方案3】:

其他答案都是正确的,但我想展示一个示例,说明 DescribeCar() 方法内部发生的情况。

public void DescribeCar()
{
    Type t = this.GetType();
    //bad hack
    dynamic _this = Convert.ChangeType(this, t);

    this.ShowDetails(); //Prints "Standard transportation."
    _this.ShowDetails(); //Prints "A roof that opens up."
}

tConvertibleCar,因为它是对象的实际类型,但this 变量(实际上是编译器隐藏的每个非静态方法的参数)的类型为Car

virtual 方法的特殊之处在于,当您的代码调用它们时,编译器会对对象的实际类型进行额外查找(即调用GetType())并检查层次结构中是否有任何类型覆盖了方法。然后它调用你的方法的最新实现。 但是,如果您使用new 而不是override,则此查找不会产生任何结果并使用基本实现。如果您使用new,调用新实现的唯一方法是将变量转换为定义新实现的类型。

【讨论】:

  • 如何确认this关键字的类型?
  • @user3723486 GetType() 方法返回对象的实际类型,而不是引用的类型。 this 引用的类型将与定义您的方法的类相同。
猜你喜欢
  • 1970-01-01
  • 2017-11-28
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-20
  • 2014-07-09
  • 1970-01-01
相关资源
最近更新 更多