c++inheritancecrtp

How does 'this' keyword in the Base template class of CRTP work?


I have been studying about CRTP and what I don't understand is in the main() where we create an object of type Base<Derived>* and invoke callDerived, how come 'this' which is an instance of Base, has all the information of Derived class too? I understand Derived inherits from Base but 'Derived' is juts template for Base but CRTP works like that is a two-way inheritance : Derived is derived from Base and Base is also derived from Derived while in this line ' Base* pObjBase = new Base();' , 'Derived' is a just template for Base!

I would like to know what is happening behind the scenes that 'this' has all the information of Derived!

  #include <iostream>
    template <typename T>
    class Base {
    public:
        virtual ~Base() = default;
        Base()
        {
            std::cout << " Base()\n";
        }
        void callDerived() {
            T& refDerived = static_cast<T&>(*this);
            refDerived.derivedMethod();
    
            T* pDerived = static_cast<T*>(this);
            pDerived->derivedMethod();
    
            //T& obj3 = dynamic_cast<T>(*this); //Error
            //T obj4 = dynamic_cast<T>(*this); //Error
            //obj3.derivedMethod();
            //obj4.derivedMethod();
           
        }
    };
    
    class Derived : public Base<Derived> {
    public:
        Derived() :
            Base()
        {
         
                std::cout << "Derived() \n";
            
        }
        void derivedMethod() {
            std::cout << "Derived method gets invoked" << std::endl;
        }
    };
    
    int main() {
        Base<Derived>* pObjBase = new Base<Derived>();
    
        pObjBase ->callDerived(); // Output: Derived method called
        delete pObjBase ;
    
    }

Solution

  • It works because you have to make sure that T is the actual type of the object. You don't make a Base<Derived> object, because that's the wrong T and it's broken, as you thought. What you're supposed to do is make a Derived object, which extends from Base<Derived>, and all is fine.

    The reason you successfully got the message Derived method gets invoked has nothing to do with templates or CRTP. It is simply because this function in the compiled code doesn't even touch the object at all. Chances are good that you can call this function on null pointers, or pointers to completely unrelated things, and it will still print the message. "It seems to work properly" is an allowed kind of undefined behaviour.