1 #include <iostream> 2 3 class Base 4 { 5 public: 6 // This version of getThis() returns a pointer to a Base class 7 virtual Base* getThis() { std::cout << "called Base::getThis()\n"; return this; } 8 void printType() { std::cout << "returned a Base\n"; } 9 }; 10 11 class Derived : public Base 12 { 13 public: 14 // Normally override functions have to return objects of the same type as the base function 15 // However, because Derived is derived from Base, it's okay to return Derived* instead of Base* 16 virtual Derived* getThis() { std::cout << "called Derived::getThis()\n"; return this; } 17 void printType() { std::cout << "returned a Derived\n"; } 18 }; 19 20 int main() 21 { 22 Derived d; 23 Base *b = &d; 24 d.getThis()->printType(); // calls Derived::getThis(), returns a Derived*, calls Derived::printType 25 b->getThis()->printType(); // calls Derived::getThis(), returns a Base*, calls Base::printType 26 }
Note that some older compilers (e.g. Visual Studio 6) do not support covariant return types.
One interesting note about covariant return types: C++ can’t dynamically select types, so you’ll always get the type that matches the base version of the function being called.
In the above example, we first call d.getThis(). Since d is a Derived, this calls Derived::getThis(), which returns a Derived*. This Derived* is then used to call non-virtual function Derived::printType().
Now the interesting case. We then call b->getThis(). Variable b is a Base pointer to a Derived object. Base::getThis() is virtual function, so this calls Derived::getThis(). Although Derived::getThis() returns a Derived*, because base version of the function returns a Base*, the returned Derived* is downcast to a Base*. And thus, Base::printType() is called.
In other words, in the above example, you only get a Derived* if you call getThis() with an object that is typed as a Derived object in the first place.
do not use virtual function in construction and destruction.