2017-08-25 120 views
1

我有作爲派生類的基類的類模板。這個想法是通過CRTP技巧來利用「靜態多態」。派生模板類對象的實例化

#include <iostream> 
template <typename T> 
class BASE 
{ 
    public: 
    void write() {static_cast<T*>(this)->write(); } 
}; 

class DER1 : public BASE<DER1> 
{ 
    public: 
    void write(){ 
     std::cout << "Calling write() inside DER1 " << number << std::endl;} 
    private: 
    int number = 11; 
}; 

我試圖2種不同實例派生類對象的方法,和,我發現的兩種方式之一是不正確的。但我不明白爲什麼。

int main(void) { 

    BASE<DER1> der1_objA ; 
    der1_objA.write(); 

    DER1 der1_objB ; 
    der1_objB.write(); 
    return 0; 
} 

事實上,我得到的輸出

Calling write() inside DER1 1880535040 [ random number] 
Calling write() inside DER1 11   [correct number ] 

可有人給我解釋一下其中的問題是什麼? 非常感謝您提前。

+4

靜態投僅在實際上是基礎子對象... –

+7

'BASE '實例中沒有'DER1'實例,但只有一個'BASE'試圖將自己投射到它不是的東西 – user463035818

+0

最後它是切片。 – user0042

回答

1

當你定義類型BASE的一個對象,它是只是基地,但你情況下,這裏面的指針的東西它不是(DER1),並繼續通過無效的指針使用它。這是未定義的行爲,垃圾是正常的結果。 CRTP工作的唯一時間是對象的動態類型實際上是傳遞給基類的模板參數。也就是說,如果BASE認爲它確實是一個DER1,它確實必須是一個DER1。鑄造本身DER1當它是唯一的基礎,並使用該指針DER1操作是不確定的行爲,從做這個沒有太大的區別:

int x = 42; 
std::string * sptr = (std::string*)&x; // extremely questionable 
sptr->clear(); // undefined behavior 

你應該考慮把基本構造都「保護」訪問級別,以防止簡單的濫用情況。這樣基本構造函數只能由派生的對象被調用,所以你不能意外實例孤立基地:

template <typename T> 
class BASE 
{ 
    protected: 
    BASE() = default; 
    BASE(BASE const&) = default; 

    public: 
    void write() {static_cast<T*>(this)->write(); } 
}; 

然後,而不是越來越垃圾,你會得到:

BASE<DER1> objA ; 
objA.write(); 

error: 'BASE<T>::BASE() [with T = DER1]' is protected within this context 
BASE<DER1> base; 
2

BASE<DER1>實例中沒有DER1實例,但只有BASE試圖將自己投射到它沒有的東西。

PS:this talk關於C++內存模型是非常相關的,但超出了我能用簡單的語言解釋的東西。