2017-08-25 5 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つの方法を試しましたが、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のオブジェクトを定義すると、 BASEですが、その中にこのポインタがない場合(DER1)、その無効なポインタを使用して使用します。これは未定義の動作であり、ガーベジは通常の結果です。 CRTPが動作するのは、オブジェクトの動的型が実際に基本クラスに渡されるテンプレートパラメータである場合のみです。つまり、BASEが本当にDER1だと思うなら、それは本当にDER1でなければなりません。

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

あなたが防ぐために、BASEのコンストラクタは、アクセスレベルを「保護」していることを検討すべきである:それは唯一のBASEで、DER1操作のためにそのポインタを使用していない多くの異なるこれをやってから、未定義の動作のときDER1に自分自身をキャスト誤用の単純なケース。あなたが誤って孤立してベースをインスタンス化することはできませんので、基本コンストラクタのみ、派生オブジェクトで呼び出すことができますこの方法:

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++メモリモデルについては、かなり関連していますが、簡単な言葉で説明できる内容を超えています。

関連する問題