Home > other >  Return type of "this" in virtual functions
Return type of "this" in virtual functions

Time:01-20

In the code I'm giving you there is E that derives from C, and I have a pointer to an object of C.

#include <iostream>
using namespace std;
class C{
  public: virtual C* f(){cout << "C::f()" << endl; return this;}
};
class E: public C{
  public: E* f(){cout << "E::f()" << endl; return this;}
};

int main(){
  C* pc = new E;
  auto p = pc->f();
  cout << typeid(p).name() << endl;
}

When I call pc->f() it goes to E::f() due to the virtual function, and I get it, but what is the return type of return this; ?

Because this is a C* but in the signature the method should return an E*. And if you run it it prints:

E::f()
P1C

CodePudding user response:

Here:

class E: public C{
  public: E* f(){cout << "E::f()" << endl; return this;}
};

a pointer to E* is returned. this is pointer to the current object, an E.

Because this is a C* but in the signature the method should return an E*.

No, this is a pointer to E* and E* can be converted to C*. It is called "covariant return type". In a nutshell: It is ok for E::f to return an E* even though it overrides C::f which returns a C*. That is because E inherits publicly from C and E* can be converted to C*.

For a caller that expects the signature as declared in C there is no issue:

 void foo(C& c) {
     C* p = c.f();  // OK!   
 }

But then why typeid tells it's a C*?

First of all you need to take care about the names. They are arbitrary. Looking only at the output of a single type name cannot tell with certainty what type it is.

Then you should do this to get the full picture:

cout << typeid(C).name() << endl;
cout << typeid(E).name() << endl; 
cout << typeid(p).name() << endl;
cout << typeid(*p).name() << endl;

Live Demo:

1C
1E
P1C
1E

p is a C*, thats the signature of C::f the virtual function you called, but the object it points to is an E.

CodePudding user response:

The type of p is C*, but the object it points to is an E.

If you print the typename of *p, you get (mangled) E.

cout << typeid(p).name() << endl << typeid(*p).name() << endl;

See it on coliru

When you call f through an E*, you get an E* back.

int main(){
  E* pe = new E;
  C* pc = pe;
  auto p1 = pe->f();
  auto p2 = pc->f();
  cout << typeid(E).name() << endl << typeid(C).name() << endl;
  cout << typeid(p1).name() << endl << typeid(p2).name() << endl;
  cout << typeid(*p1).name() << endl << typeid(*p2).name() << endl;
}

More coliru

  • Related