2010-02-24 78 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; 
} 
再次

它打印 「在C」

這是怎麼回事?

+1

不可讀的代碼。 – Drakosha 2010-02-24 10:41:00

+1

你會期望它打印什麼呢? – sth 2010-02-24 10:41:53

+0

在第二種情況下「在B中」,然後是「在C中」? – nakiya 2010-02-24 10:53:11

回答

1

你叫誰重載了這個功能的C類對象的虛成員函數。它要求在C類功能

此外,這不是CRTP作爲模板類B沒有從類模板參數繼承。

+0

原代碼(你之前修復)缺少了不少必要的東西,所以這是很難說有什麼最初的意思。也許CRTP的東西也不小心丟失了...... – user64075 2010-02-24 10:51:56

+0

你是什麼意思,這不是CRTP?你的意思是B應該繼承C嗎? – nakiya 2010-02-24 10:54:09

+0

號CRPT意味着乙應從T. – 2010-02-24 12:12:49

1

Func是虛擬的,a是指向的C一個實例,因此C的版本的Func被調用。

+0

繼承但在第二情況下的是B型的 nakiya 2010-02-24 11:01:44

+1

*隨着虛擬函數的指針的類型並不重要。指向對象的動態類型很重要,並且在這兩種情況下都會創建一個C. – UncleBens 2010-02-24 11:18:15

+0

@nakiya:B​​ *源自A. A :: Func是虛擬的,所以B :: Func是虛擬的而C :: Func是虛擬的。 – 2010-02-24 11:53:49

0

的代碼是不完整的,添加#和「使用命名空間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://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – Blaisorblade 2010-05-05 17:01:31