1

私があなたの注意を引きたいと思うことがはっきりしないことがあります、それらのコードスニペットをチェックしてください:

template< typename DerivedClass >
class construction_management
{
    city* this_city;
public:
    construction_management()
    {
        this_city = static_cast< city* >(this);
    }
    ~construction_management();
};

不要なコードをすべて意図的に削除しました。以下のように定義されている、タイプ「city」への「this」ポインターの静的キャストを作成するコンストラクターを確認してください。

class city : public construction_management< city >
{

public:

public:
    city( const string& name, const string& owner );
};

クラスに含めることができるものはここでは関係ないと思うので、クラスは意図的に空になっています。ここで何が起こっているのかを100%理解できないようにしたい場合、g ++ 4.7.2はコンパイル段階で警告やエラーを出力せず、「this_city」ポインターを使用するたびに、市のすべてのパブリックメンバーにアクセスできます。すべての変数が適切に初期化され、常に有効なデータが含まれているため、オブジェクト自体は一貫しているように見えます。

私が知りたいのは、construction_managementを単純な非テンプレートクラスとして定義した場合にこのコードが機能しないのはなぜですか?constからconst以外の都市へのポインタへの暫定的な変換が原因で、キャストが失敗します。なぜですか?

これはエラー印刷です:

game.hpp: In constructor 'city_manager::construction_management::construction_management()':
game.hpp:164:41: error: invalid static_cast from type 'city_manager::construction_management* const' to type 'city_manager::city*'

そして、construction_managementがテンプレートである場合、なぜ機能するのでしょうか。これは一種のCRTPですか?

皆さん、ありがとうございました。

4

1 に答える 1

4

これはCRTPであり、遅延テンプレートのインスタンス化のために機能します。

この線:

this_city = static_cast< city* >(this);

thisに変換可能である必要がありcity*ます。cityから派生した場合は機能しconstruction_managementます。ただし、基本クラスは派生クラスの前に完全な宣言を持っている必要があるため、それを記述する方法は1つしかありません。

//template code may or may not be present
class construction_management {...};
//maybe more code here
class city: public construction_management {...};

基本クラスがテンプレートでない場合は、コンパイラが最初にコードを確認したときにインスタンス化されます。次に、コンパイラーはコンストラクターにぶつかり、その時点で何cityから派生したのか(または、不完全な型として宣言されていない場合はconstruction_managementaが何であるかさえ)わからず、あきらめます。city

ただし、基本クラスがテンプレートの場合、継承が宣言されたときにインスタンス化されます(とにかく、その頃のどこかで、私はこれに関する専門家ではありません)。その時点で、コンパイラはそれcityがから派生していることを認識しconstruction_management<city>、すべてが機能します。

同じ理由で、コンストラクター定義を後でコンパイルされるファイル(ほとんどの場合.hから.cpp)に移動すると、テンプレートがなくても機能します。

于 2013-01-03T11:42:37.620 に答える