2010-02-24 4 views
1

У меня есть эти 3 класса.Наследование с использованием CRTP

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; 
     } 
}; 

И, я делаю это:

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

    return 0; 
} 

И печатает: "В C".

Если я сделаю это,

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

    return 0; 
} 

Это снова печатает "В С"

Что происходит?

+1

нечитаемый код. – Drakosha

+1

Что бы вы ожидали от печати? – sth

+0

Во втором случае «В B», затем «В C»? – nakiya

ответ

1

Вы вызываете функцию виртуального члена объекта класса C, который перегрузил эту функцию. Он вызывает функцию в классе C.

Кроме того, это не CRTP, поскольку шаблонный класс B не наследуется от параметра шаблона класса.

+0

Исходный код (до вашего исправления) не хватало достаточно большого количества необходимого материала, поэтому трудно сказать, что изначально предназначалось. Возможно, CRTP-материал тоже был случайно потерян ... – user64075

+0

Что значит это не CRTP? Вы имеете в виду, что B должен наследовать от C? – nakiya

+0

№ CRPT означает, что B должен наследовать от T. –

1

Func является виртуальным, a является указателем на экземпляр C, поэтому версия FuncC «s называется.

+0

Но во втором случае a имеет тип B * – nakiya

+1

С виртуальными функциями тип указателя не имеет значения. Динамический тип заостренного объекта имеет значение, и вы создаете C в обоих случаях. – UncleBens

+0

@nakiya: B * получен из A. A :: Func является виртуальным, поэтому B :: Func является виртуальным и C :: Func является виртуальным. –

0

Код не является полным, добавьте #include и "using namespace std;". Что еще более важно, вы получаете желаемое поведение, удалив объявление виртуальной функции в A. В общем, основной причиной использования CRTP является то, что шаблон может знать тип, который он получает, и избегать виртуального вызова (или, лучше, избегать создания метод виртуальный).

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 
    } 
}; 
+0

См. Также: http://ru.wikipedia.org/wiki/Curiously_recurring_template_pattern – Blaisorblade

Смежные вопросы