2

My fret is: In the code presented below, it should display A then B. But it displays B then B. Why is it so?

What I feel is, constructor of A gets executed first when creating object of B. In that case, the method in B would not be hitted right? So it should be A.Display() and should result A. Also, then a.Display() should return B because we have override.

So I expect A then B. Because its not overloading but overriding. I know the definition of these things, I expect to understand the reason for this behavior and how it works internally as I am not convinced with BB but AB.


Code

class A
{
    public A()
    {
        this.Display();
    }
    public virtual void Display()
    {
        Console.WriteLine("A");
    }
}

class B :A
{
    public override void Display()
    {
        Console.WriteLine("B");
    }
}

class C
{
    static void Main()
    {
        A a = new B();
        a.Display();
        Console.WriteLine();
        Console.ReadLine();
    }
}

Outputs

1) On override of Display method in the derived class yields the following:

A a = new A(); // ---> AA
B a = new B(); // ---> BB // I expect AB.
A a = new B(); // ---> BB // I expect AB.

2) using the NEW keyword in the Display method in derived class yields the following:

B a = new B(); // ---> AB // I Expect AA here.
A a = new B(); // ---> AA
A a = new A(); // ---> AA

3) More interesting findings are:

When I use base.Display() in the derived constructor with override of the base method in derived class, it gives me BAB

I do not see any logic at least in this. because, it should give BBB

Szymon
  • 42,577
  • 16
  • 96
  • 114
Jasmine
  • 5,186
  • 16
  • 62
  • 114
  • When constructor of A runs, you actually in B. Therefore, since `Display` is overriden, `this.Display` returns B – T.S. Dec 06 '13 at 03:33
  • @OldProgrammer: Not at all. I DO NOT need definition of overload or override. I completely understand that. But I do not understand this behavior. I expect A. I DO NOT expect B. I expect A first. Then B. – Jasmine Dec 06 '13 at 04:00
  • As @Szymon explains in his answer, when you have an object of type `B` the constructor in `A` calls the method `Display` of `B`. This is so because you are overriding and not hiding the method of the base class. So, in an object of type `B` the method `Display` from the class `A` "is not there"* (because you did override it), if you had hidden it instead it would behave as you expect. *: you can still get it with `base.Display` as per Zerkey's answer. – Theraot Dec 06 '13 at 06:45
  • @Theraot: No no no, I am happy with few outputs but not happy with few other strange outputs. Till now I thought I was knowing overriding. Its very funny now. This behaves differently now. Please see all scenarios I explained above and I highlighted where I have concerns. (points 1, 2, 3). – Jasmine Dec 06 '13 at 06:49
  • I have done an edit to your question, I would go though each single output in an answer. By the way: there is no "overloading" (at least not as understood in C#), using the keyword "new" is not overloading it is hidding. – Theraot Dec 06 '13 at 07:04
  • @Theraot: Thank you so much, I am going through the recent answers by you and Eric. – Jasmine Dec 06 '13 at 08:12
  • Is the last answer in NEW section correct? It's the same one as first but with a different result. I guess it should be `A a = new A()`. – Szymon Dec 06 '13 at 08:15
  • @Szymon: You are right, sorry for the error. That should be AB as per the output. – Jasmine Dec 06 '13 at 08:24

5 Answers5

9

What I feel is, constructor of A gets executed first when creating object of B.

Correct.

In that case, the method in B would not be hit right?

This is incorrect.

In similar code in C++ you would be correct. In C++ there is a rule that virtual function dispatch tables are built as the object is being constructed. That is, when the "A" constructor is entered, the vtable is filled in with the methods in "A". When control goes to the "B" ctor, the vtable is then filled in with the methods of B.

This is not the case in C#. In C# the vtable is filled in the moment the object comes out of the memory allocator, before either ctor is executed, and it does not change after that. The vtable slot for the method always contains the most derived method.

Therefore calling a virtual method in a ctor as you are doing here is a very bad idea. A virtual method can be called where the implementation is on a class whose ctor has not run yet! It might therefore depend on state that has not yet been initialized.

Note that field initializers run before all ctor bodies, so fortunately an override on a more derived class will always run after the field initializers of the overriding class.

The moral of the story is: simply don't do that. Don't ever call a virtual method in a ctor. In C++ you might get a different method than you expect, and in C# you might get a method that uses state that is not initialized. Avoid, avoid, avoid.

Why we shouldn't call virtual methods inside ctor? Is it because we get only the (latest derived) results only) always in the vtable?

Yes. Let me illustrate with an example:

class Bravo
{
    public virtual void M() 
    {
        Console.WriteLine("Bravo!");
    }
    public Bravo()
    {
        M(); // Dangerous!
    }
}
class Delta : Bravo:
{
    DateTime creation;
    public override void M() 
    {
        Console.WriteLine(creation);
    }
    public Delta() 
    {
        creation = DateTime.Now;
    }
}

OK, so the expected behavior of this program is that when M is called on any Delta, it will print out the time that the instance was created. But the order of events on new Delta() is:

  • Bravo ctor runs
  • Bravo ctor calls this.M
  • M is virtual and this is of runtime type Delta so Delta.M runs
  • Delta.M prints out the uninitialized field, which is set to the default time, not the current time.
  • M returns
  • Bravo ctor returns
  • Delta ctor sets the field

Now do you see what I mean when I say that the overriding method might rely on state that is not initialized yet? In any other usage of M, this would be fine because the Delta ctor would already be finished. But here M is called before the Delta ctor even starts!

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    Thank you so much Eric for the wonderful explanation. I never knew about vtables and states. I will not use such virtual methods inside the constructor. I will read all your 3 part tutorials that was referred by Theraot. Thank you so much for your time and help :) :) – Jasmine Dec 06 '13 at 08:21
  • Eric, one more small or silly clarification, perhaps I am not able to understand it fully. Why we shouldn't call virtual methods inside ctor? Is it because we get only the (latest derived) results only) always in the vtable? Which confused me in my question scenario in my post? – Jasmine Dec 06 '13 at 08:48
  • 1
    @Divine Check: http://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor Abstract: 1) open the door for derived classes to alter the initialization of the fields of the base class. 2) allow methods in the derived class to run while the fields of the derived class has not have been initialized yet (the constructor of the derived class is yet to run). 3) a derived class of the derived class may mess up what the derived class did by overriding the virtual methods. It is not an outright bad thing, it is sometimes useful (I have used that myself) but may be hard to get right. – Theraot Dec 06 '13 at 09:03
  • 1
    @Divine: You are very welcome! I've updated the answer to address your follow-up question. – Eric Lippert Dec 06 '13 at 17:13
  • @Theraot: Thank you for the link and explanation, that's makes it clear :) :) – Jasmine Dec 07 '13 at 02:36
  • @EricLippert: Thank you so much, that's perfect and simple example which makes me understand :) Great learning for me :) :) Cheers – Jasmine Dec 07 '13 at 02:37
3

You create an instance of an object B. It uses the code of the constructor that is defined on class A as you did not override it in B. But the instance is still B, so other methods called in the constructor are the ones defined in B, not A. Hence you see the result of Display() defined in class B.

Update based on update of the question

I'll try to explain the "weird" results you're getting.

When overriding:

B a = new B(); // ---> BB // I expect AB.

A a = new B(); // ---> BB // I expect AB.

This is covered above. When you override a method on a child class, this method is used if you're using an instance of the child class. This is a basic rule that the methods used are decided by the class of the instance of a variable, not by the class used to declare the variable.

When using new modifier for the method (hiding inherited method)

B a = new B(); // ---> AB // I Expect AA here.

Now there's two different behaviours here:

  • When the constructor is used, it's using the constructor in class A. As the inherited method is hidden in the child class, the constructor is using Display() method from class A and hence you see A printed.

  • When you later call Display() directly, the instance of the variable is B. For that reason, it uses the method defined on class B which prints B.

Community
  • 1
  • 1
Szymon
  • 42,577
  • 16
  • 96
  • 114
  • Mate, you are wrong. I am making the override as new in the derived class. And when I say A a = new B(), it gives me AA and when I say B a = new B(), it gives me AB. I find it funny lol. How can it be so silly, you DO NOT even create an object of B first. You create object of A when it refers to constructor of A. – Jasmine Dec 06 '13 at 06:23
  • Let me go thorough that again when I get home later. – Szymon Dec 06 '13 at 06:26
  • Thank you. Again, when I say A a = new A(), it gives me AA. I really find it STRANGE and cannot understand how it works. Anyway, thank you so much for your time. Lets figure out what's happening. – Jasmine Dec 06 '13 at 06:28
  • Thanks Szymon, well I understood the definition of overriding. However, my all doubt was, although the first thing to get hit in all these executions in my code above is base class constructor, as I do not have any other private fields. Now, my question was why that cons call should yield A but other result in some contexts. Now I am clear that, vtables inside the CLR/.NET is responsible for this which stores the latest overrides result. And when we call the method, looks like vtable gives the latest. Please follow Eric Lippert's post below which I am following too. vtable is the mystery. – Jasmine Dec 06 '13 at 08:39
3

Initial statement

I'll start with the base code, I have adapted it to run in LINQPad (I did also change it to Write instead of WriteLine because I'll not preserve the new lines in the explanation anyway).

class A
{
    public A()
    {
        this.Display();
    }

    public virtual void Display()
    {
        Console.Write("A"); //changed to Write
    }
}

class B :A
{
    public override void Display()
    {
        Console.Write("B"); //changed to Write
    }
}

static void Main()
{
    A a = new B();
    a.Display();
}

The output is:

BB

In your initial question you said you were expecting:

AB

Whats happening here (as Szymon attempted to explain) is that you are creating an object of type B and the class B overrides the method Display of the class A. So whenever you call Display on that object it will be the method of the derived class (B), even from the constructor of A.


I will go over all the cases you mention. I want to encourage to read it carefully. Also, be open minded because this does not match what happens in certain other languages.


1) On override of Display method in the derived class

This is the case where you are overriding the method, ie:

public override void Display()
{
    Console.Write("B"); //changed to Write
}

When you override, for all practical uses the method that will be used is the method of the derived class. Think of override as replace.

Case 1:

A a = new A(); // ---> AA

We are ok, with that.

Case 2:

B a = new B(); // ---> BB // I expect AB.

As mentioned above, calling Display on the object will always be the method on the derived class. So, both calls to Display yield B.

Case 3:

A a = new B(); // ---> BB // I expect AB.

This is a variant of the same confusion. The object is clearly of type B, even if you have it in a variable of type A. Remember that in C# the type is a property of the of the object not of the variable. So, the result is the same as above.


Note: You can still use base.Display() to access the method that was replaced.


2) Using the NEW keyword in the Display method in derived class

This is the case where you are hiding the method, ie:

public new void Display()
{
    Console.Write("B"); //changed to Write
}

When you hide the method, it means that the original method is still available. You can think of it as a different method (that happens to have the same name and signature). That is: the derived class is not replacing overriding that method.

Because of that, when you do a (virtual) call to the object where at compile time it was decided it was going to use the method of the base class... the method of the derived class is not taken into consideration (in practice, it acts as it weren't a virtual call).

Think of it like this: if you call the method using a varible of the base class... the code is not aware that there exists a derived class that hides the method and that that particular call may be executed with one of those object. Instead, it will use the method of the base class, regardless.

Case 1:

B a = new B(); // ---> AB // I Expect AA here.

You see, at compile time the call in the constructor was set to use the method of the base class. That one gives A. But since the variable is of type B the compiler is aware that the method was hidden for the second call.

Case 2:

A a = new B(); // ---> AA

Here, neither in the constructor nor in the second call it will use the new method. It is not aware of it.

Case 3:

A a = new A(); // ---> AA

And I think this one is clear.


3) Using base.Display()

This the variant of the code where you do this:

public new void Display()
{
    base.Display();
    Console.Write("B"); //changed to Write
}

base.Display() is gonna be the method in the base class (A), no matter what.


Further reading

You said you want to learn how this works internally.

You can go deeper by reading Microsoft's C# Spec on Virtual Methods

Then read Eric Lippert's Implementing the virtual method pattern in C# (part 1, part 2 and part 3)

You may also be interested:


Others explanations of Virtual Methods from the web:

Community
  • 1
  • 1
Theraot
  • 31,890
  • 5
  • 57
  • 86
  • Thank you so much Theraot for such a detailed explanation of every behaviors, it helps me. Thank you so much for the pointers to reading guides on this more, I will read all these links and understand it better. vtable concept I do not know and that is something which I wanted to know (As in who is responsible for this behavior). Thank you so much, your in depth writings are very helpful for me to understand. Thank you for your time :) Cheers :) – Jasmine Dec 06 '13 at 08:42
0

You may be confusing yourself by naming the class a while instantiating it as class B. If you are looking to call the virtual method you could use the base keyword. The following code writes A B

class A
{
    public A()
    {
        //this.Display();
    }
    public virtual void Display()
    {
        Console.WriteLine("A");
    }
}

class B : A
{
    public override void Display()
    {
        base.Display();
        Console.WriteLine("B");
    }
}

class C
{
    static void Main(string[] args)
    {
        A a = new B();
        a.Display();
        Console.WriteLine();
        Console.ReadLine();
    }
}

Also note you can see why your code is displaying B B by setting a breakpoint at the beginning and then walking through your code execution line-by-line (F11).

Zerkey
  • 795
  • 1
  • 6
  • 16
  • "naming the class a while instantiating it as class B" This sounds wrong. A person did what he/she did and asked what he/she want. All it was is declare variable as base type and assigned a concrete type, which is normal. You've changed the code, so your answer is not valid and wrong – T.S. Dec 06 '13 at 03:46
  • Well of course I changed the code, the guy mentioned three times he wants `A B` as a result so I commented one line and added one line of code. I merely suggested he might change the name of `a` to `b` because a is in fact class B, as the debugger will tell you. – Zerkey Dec 06 '13 at 03:53
  • Agree on first part but `A a = new B();` is correct code. Assign concrete instance to base type variable is good – T.S. Dec 06 '13 at 03:56
  • His code reads like this: `Animal animal = new Cat()` Later in the code when you are referencing `animal` it is actually a `Cat`, and would have been better practice to write `Animal cat = new Cat()` ... That is all I meant by my words. – Zerkey Dec 06 '13 at 03:59
0

What I understood is , in case of virtual method, same method slot is shared among the parent and child object.

If so, then I think when an object virtual method is called , by somehow compiler updates the method slot with appropriate method address so that exact method is jitted and executed In c#.