简体   繁体   中英

c#: flow of control when calling an inherited base method, which inturn calls a base virtual method which is set as new in derived class

disclaimer: i am totally newbie to this world of coding! in my course on learning c#, i read this article. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/knowing-when-to-use-override-and-new-keywords .

code:

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

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

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

ConvertibleCar myCC = new ConvertibleCar();
myCC.DescribeCar();
myCC.ShowDetails();

//Output
Car: Four wheels and an engine.
Car: Standard transportation.
ConvertibleCar: A roof that opens

Question: i expect with my understanding i should get "ConvertibleCar: A roof than opens" in my second and third line of output. what is it different when calling ShowDetails directly on the derived class, and from within a method in the base class. PS: the showdetials is set at new in the derived class.

Because with new you effectively shadowed ShowDetails (in fact, in VB.NET there's a Shadows keyword for this). Moreover, with new you can make ShadowDetails a property!

Let's create two classes: Base and Derived:

class Base
{
    public virtual int GetInt()
    {
        return 10;
    }
}

class Derived : Base
{
    public new int GetInt()
    {
        return 11;
    }
}

Now, let's test them:

Base b;
Derived d;
int x;

b = new Derived();
d = new Derived();

x = b.GetInt(); // x = 10 [Base.GetInt()]
x = d.GetInt(); // x = 11 [Derived.GetInt()]

As you see, although b is assigned Derived, it still refers to Base .

But let's do something completely different - let's turn method into a property!

class Derived : Base
{
    public new int GetInt
    {
        get { return 11; }
    }
}

Now when we run previous test code we will see that x = 10 :

x = d.GetInt(); // x = 10

But, wait, we don't have GetInt() method in Derived class! Why the code is compiled? It's simple - because we shadowed GetInt() method with GetInt property, now GetInt() is called from Base ! To confuse things more, the IntelliSense doesn't show GetInt() method on d variable, but the compiler is satisfied. To get 11, you need to call property:

x = d.GetInt;

You can also turn GetInt() method into delegate:

class Derived : Base
{
    public new delegate int GetInt();
}

and use it:

Derived.GetInt getIntDelegate = () => 12;
Console.WriteLine(getIntDelegate()); // Prints 12

The new keyword used for the hiding base member/method. So

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

ShowDetails method is a new method for ConvertibleCar class and the base class ShowDetails method is completely different and it is not in the inheretance chain. Imagine that, you could define the method name like ShowDetails2 in the ConvertibleCar class. It would be same case.

Also, if you use the override keyword instead of new , the ConvertibleCar class would override the ShowDetails method.

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

And output would be;

Car: Four wheels and an engine.
ConvertibleCar: A roof that opens.
ConvertibleCar: A roof that opens.

To get your expected output, use override in place of new :

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

If you use new , you shadowed the ShowDetails method in the base class. This means that the derived class implementation will only be used when you call the method from a derived class variable.

override does something different. If ShowDetails is overridden, then the derived class implementation will always be used as long as the object's underlying type is the derived class, no matter the type of the variable.

This explains why the second line of output is different. The second line is produced from this line:

public void DescribeCar()
{
    Console.WriteLine("Car: Four wheels and an engine.");
    ShowDetails(); <--------
}

ShowDetails means this.ShowDetails . this is of type Car but actually refers to an object of ConvertibleCar . Since ShowDetails is shadowed, it calls the implementation of Car (because this is of type Car !)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM