3

If I have something like this:

class Base
{
    public void Write()
    {
     if (this is Derived)
      {
         this.Name();//calls Name Method of Base class i.e. prints Base
        ((Derived)this).Name();//calls Derived Method i.e prints Derived 
      }
     else
      {
        this.Name();
      }
    }

    public void Name()
    {
        return "Base";
    }
}

class Derived : Base
{
    public new void Name()
    {
        return "Derived";
    }
}

and use the following code to call it,

Derived v= new Derived();
v.Write(); // prints Base

then the Name method of base class gets called. but what would be the actual type of this keyword in the Write method? if that is of Derived type(as the Program control enters the first if block in Write method) then it is calling the base Name method, and why does the explicit casting,(Derived)this, change the call to the Name method of derived class?

user3723486
  • 189
  • 1
  • 3
  • 12

4 Answers4

7

this will always be of the derived class type.

The reason why in the call this.Name(); calls the base class Name() method is because Name is not defined as a virtual method, thus it is being linked in compile time when the compiler knows nothing about the actual type of this that it will have at this point.

One more note regarding the code above. Generally in product code referring to a Derived class from the Base class explicitly is really a bad practice as it breaks one of the OOP principles that the Base class should not be aware about the classes which inherit it. However, assuming that the code above was just used for C++ investigation then this is of course ok.

Amnon Shochot
  • 8,998
  • 4
  • 24
  • 30
  • then what about `((Derived)this).Name()`? – user3723486 Apr 24 '15 at 22:14
  • Also in this case there will be static binding to function `Name`, this time to the Derived class version. The difference, however, is that in this case you're explicitly instructing the compiler to treat `this` as an object of type Derived, thus the compiler translate the call to `Name()` to the address of the implementation in the derived class. – Amnon Shochot Apr 24 '15 at 22:16
  • if I mark the `Name()` method as `virtiual`, the behavior would be the same? – user3723486 Apr 24 '15 at 22:18
  • It is helpful to separate the compile-time type from the actual type at run-time. `this` is of compile-time type `Base`. The overload resolution (binding) at compile-time reflects that. At run-time the type could be more specific (and is in this example), but the binding is already fixed. One can use `((dynamic)this).Name()` to have the binding happen based on the actual run-time type. – Jeppe Stig Nielsen Apr 24 '15 at 22:19
  • If you'll define `Name()` as `virtual` then the behavior will not be the same as in this case the Derived class version of `Name()` will be called rather than the Base version as in your original code. – Amnon Shochot Apr 24 '15 at 22:24
  • this happens only if you override it in the base, right? – user3723486 Apr 24 '15 at 22:26
  • (Of course the declaration in `Derived` must use `override`, not `new`, if we want this virtual dispatch.) – Jeppe Stig Nielsen Apr 24 '15 at 22:27
  • And calling the inherited `Write` method from Derived class has no effect on the `this` compile -time binding? – user3723486 Apr 24 '15 at 22:39
  • Since the only `Write` method defined is in the base class then the compiler will translate any call to this method from the derived class to the base class implementation. – Amnon Shochot Apr 24 '15 at 22:53
  • @Jeppe Stig Nielse. `this` is of compile-time type Base, So it is not always be of the derived class type? – user3723486 Apr 24 '15 at 23:00
  • @user3723486 The compile-time type is "always" `Base`, which means when you compile your program into bytecode the type the C# compiler uses for the `this` value is `Base`. The run-time type depends. If you said `(new Base()).Write()`, the run-time type would be `Base`. But since `v` is a `Derived` in your program, `v.Write()` leads to `this` being of run-time type `Derived`. Please understand that *compile-time* type ("declared" type) and *run-time* type ("actual" type) are two distinct notions. – Jeppe Stig Nielsen Apr 25 '15 at 06:59
  • Indeed it does, even for class indexers .. `this["key"]` ... will resolve to the derived type even if it is called in the base class. – CAD bloke Jun 14 '19 at 05:46
2

You should be using virtual and override if you want to access any overridden members in a derived class:

class Base
{
    public void Write()
    {
     if (this is Derived)
      {
         this.Name();//calls Name Method of Base class i.e. prints Base
        ((Derived)this).Name();//calls Derived Method i.e prints Derived 
      }
     else
      {
        this.Name();
      }
    }

    public virtual void Name()
    {
        return "Base";
    }
}

class Derived : Base
{
    public override void Name()
    {
        return "Derived";
    }
}
Ron Beyer
  • 11,003
  • 1
  • 19
  • 37
  • No need to use `Override` in the derived class - the fact that the method was defined as virtual in the base class means that the call will be done via the vtable that will redirect the call to the implementation of `Name()` in the derived class. – Amnon Shochot Apr 24 '15 at 22:07
  • 1
    You must use `override`. Absence of `override` leads to a `new` method which has no relation to the `virtual` method inherited, and has no place in that "vtable". – Jeppe Stig Nielsen Apr 24 '15 at 22:32
1

This is all your need. You do not need to and should not be checking the type from the base to handle logic. Any special logic should be be handled in the derived classes and probably want to mark methods up as virtual in the base and override in the derived classes.

class Base
{
    public void Write()
    {
        SomeWriteMethod(Name());
    }

    public virtual void Name()
    {
        return "Base";
    }
}

class Derived : Base
{
    public override void Name()
    {
        return "Derived";
    }
}

If you want the actual name of the class in Name(), you just need to call GetType().Name in the base and it will automatically work for any derived classes as GetType() returns you the actual instanced type of the instance. Just like GetType() is of the actual instance, this is also your actual instance so any special logic will be of that class' implementation.

this is actually a redundant call in your base class. Either you specify it or you don't -- you get the same result. The reason you see mixed results is because you used the new operator. new only works when you are working with that explicit type. It basically hides other implementations in the chain. And so, this being in the context of Base is going to give your Base.Name() where as if you had overridden, Derived.Name() would have been used instead.

MSDN: Knowing when to use override and new keywords

Here is an excellent answer about new -- Why does calling a method in my derived class call the base class method?

Community
  • 1
  • 1
TyCobb
  • 8,909
  • 1
  • 33
  • 53
0

By casting ((Derived)this).Name(), you are explicitly setting it to the derived class. Since you have Write defined in the base class, this will point method calls to it. This behavior occurs because you have not overridden the base method and you are calling it from the base class.

beautifulcoder
  • 10,832
  • 3
  • 19
  • 29