Унаследованный метод не имеет доступа к новой реализации в производном классе

Как указано в этой статье MSDN:

Объект типа производного класса не имеет доступа к новому переопределенному методу, унаследованному от базового класса, и к вызову объекта производного класса из ShowDetails() Метод внутри унаследованного метода DescribeCar() сделано в ShowDetails() Метод базового класса.

если 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.

3 ответа

Решение

new скрывает старый метод, что означает, что если вы напрямую вызываете его на ConvertibleCar Например, вы получите поведение производного класса, но оно не будет вызываться полиморфно.

Когда базовый класс вызывает его, он вызывает виртуальный метод, который, поскольку он не был переопределен, вызывает метод базового класса. Вместо использования метода скрытия (который вы почти никогда не используете), просто переопределите его:

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

Ну, когда вы думаете об этом - не думайте о наследовании - это все равно что спрашивать, почему 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 поэтому не может вызвать метод.

Другие ответы верны, но я хочу показать пример того, что происходит внутри 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."
}

t является ConvertibleCar потому что это фактический тип объекта, но this переменная (которая на самом деле является параметром каждого нестатического метода, скрытого компилятором) имеет тип Car,

Конкретная вещь о virtual методы в том, что когда они вызываются вашим кодом, компилятор выполняет дополнительный поиск фактического типа объекта (т.е. вызывает GetType()) и проверяет, переопределил ли какой-либо тип в вашей иерархии метод. Затем он вызывает новейшую реализацию вашего метода. Но если вы используете new вместо overrideэтот поиск не дает результатов и используется базовая реализация. Если вы используете new единственный способ вызвать новую реализацию - привести вашу переменную к типу, в котором была определена новая реализация.

Другие вопросы по тегам