views:

137

answers:

3

I have these 3 classes.

class A  
{  
    public:  
        virtual void Func() = 0;  
};

template<class T>  
class B : public A  
{  
    public:  
        void Func()  
        {  
            cout << "In B" << endl;  
            static_cast<T*>(this)->Func();  
        }  
};  

class C : public B<C>  
{  
    public:  
        void Func()  
        {  
            cout << "In C" << endl;  
        }  
};  

And, I do this:

int main(int argc, char **argv)  
{  
    A *a = new C;  
    a->Func();  

    return 0;  
}  

And it prints : "In C".

If I do this,

int main(int argc, char **argv)  
{  
    B<C> *a = new C;  
    a->Func();  

    return 0;  
}  

It again prints "In C"

What is going on?

+1  A: 

You're calling a virtual member function of a class C object who has overloaded this function. It calls the function in class C.

Furthermore, this is not CRTP as the templated class B does not inherit from the class template parameter.

Didier Trosset
The original code (before your fix) lacked quite a lot of necessary stuff, so it's hard to say what was originally meant. Perhaps the CRTP stuff was accidentally missing too...
What do you mean this is not CRTP? DO you mean B should inherit from C?
nakiya
No. CRPT means that B should inherit from T.
Didier Trosset
+1  A: 

Func is virtual, a is a pointer to an instance of C, so C's version of Func is called.

Joe Gauterin
But in the second case a is of type B<C>*
nakiya
With virtual functions the type of the pointer doesn't matter. The dynamic type of the pointed object matters, and you create a C in both cases.
UncleBens
@nakiya: B<C>* is derived from A. A::Func is virtual, so B<C>::Func is virtual and C::Func is virtual.
Joe Gauterin
A: 

The code is not complete, add #include and "using namespace std;". More importantly, you get the desired behaviour by removing the virtual function declaration in A. In general, the main reason to use CRTP is to let the template know the type it receives and avoid doing a virtual call (or better, avoid making the method virtual).

template <typename T>
class ClassUsingSomething {
  public:
    void method1() {
      // I need to call method2, I do this by casting, so it doesn't need to be virtual.
      static_cast<T *>(this)->method2();
    }
};

class A: public ClassUsingSomething<A> {
  public:
    void method2() {
      //do something
    }
};
Blaisorblade
See also:http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Blaisorblade