echo()「のコンストラクターからは呼び出せない」というJamesMcNellisの答えFoo<T>はほぼ正しいです。
Foo<T>コンストラクターの本体がFoo<T>実行されている間、オブジェクトはタイプであるため、コンストラクターから仮想的に呼び出すことはできませんFoo<T>。派生クラスの部分はまだありません。そして、あなたのコードのように、の仮想呼び出しはecho()、純粋仮想関数に行きます:bang、dead。
ただし、のような純粋仮想関数の実装を提供し、コンストラクターからのecho()ように非仮想的に呼び出すことができます。:-)それが実装を呼び出すことを除いて。派生クラスの実装を呼び出したいようですが。Foo::echo()FooFoo
今あなたの問題に関して:
「コンストラクターでその関数が本当に欲しいのです。」
さて、私がこれを書いているとき、あなたの(無効な)コードは次のようになります:
template <typename T> class Foo
{
public:
Foo(T a)
{
x = a;
echo();
}
protected:
T x;
virtual void echo() = 0;
};
class Bar : public Foo<int>
{
public:
Bar(int a) : Foo<int>(a)
{
}
void echo();
};
void Bar::echo()
{
cout << "value: " << x << endl;
}
int main(int argc, char* argv[])
{
Bar bar(100);
return 0;
}
そして、私があなたの問題の説明を理解している限り、Fooコンストラクターがechoから継承するクラスの実装を呼び出すようにしFooます。
これを行うにはいくつかの方法があります。それらはすべて、派生クラスの実装に関する知識を基本クラスにもたらすことです。
1つはCRTP、不思議なことに繰り返されるテンプレートパターンとして知られており、特定の問題に適応して次のようになります。
#include <iostream>
template< class XType, class Derived >
class Foo
{
public:
Foo( XType const& a )
: state_( a )
{
Derived::echo( state_ );
}
protected:
struct State
{
XType x_;
State( XType const& x ): x_( x ) {}
};
private:
State state_;
};
class Bar
: public Foo< int, Bar >
{
private:
typedef Foo< int, Bar > Base;
public:
Bar( int a ): Base( a ) {}
static void echo( Base::State const& );
};
void Bar::echo( Base::State const& fooState )
{
using namespace std;
cout << "value: " << fooState.x_ << endl;
}
int main()
{
Bar bar(100);
}
上記は悪くない解決策ですが、どちらも良くありません。実際の問題が基本クラスコンストラクターから派生クラスの非静的メンバー関数を呼び出すことである場合、唯一の「良い」答えはJavaまたはC#であり、これによりそのようなことが可能になります。派生クラスオブジェクト内のまだ初期化されていないものに誤ってアクセスしようとするのは非常に簡単であるため、C++では意図的にサポートされていません。
とにかく、ほとんどいつものように、何かのコンパイル時の解決策がある場合、実行時の解決策もあります。
次のように、実行する関数をコンストラクター引数として渡すだけです。
#include <iostream>
template< class XType >
class Foo
{
protected:
struct State
{
XType x_;
State( XType const& x ): x_( x ) {}
};
public:
Foo( XType const& a, void (*echo)( State const& ) )
: state_( a )
{
echo( state_ );
}
private:
State state_;
};
class Bar
: public Foo< int >
{
private:
typedef Foo< int > Base;
public:
Bar( int a ): Base( a, echo ) {}
static void echo( Base::State const& );
};
void Bar::echo( Base::State const& fooState )
{
using namespace std;
cout << "value: " << fooState.x_ << endl;
}
int main()
{
Bar bar(100);
}
これらの2つのプログラムを研究すると、おそらく微妙な違いに気付くでしょう(コンパイル時と実行時の知識の伝達に加えて)。
最後に、ダーティキャストを含むソリューションがあり、C ++型システムには、メンバーポインターを使用して、キャストせずに保護された基本クラスの状態にアクセスできる抜け穴もあります。前者は危険であり、後者はあいまいで、おそらく非効率的です。だから、しないでください。
しかし、うまくいけば、上記の解決策の1つがあなたに合うか、またはいくつかの適切な適応になります。
ちなみに、あなたがインスタンスであると思われるより一般的な一連の問題は、DBDI、初期化中の動的バインディングとして知られています。C ++ FAQアイテム23.6でより一般的な扱いを見つけることができますが、基本クラスのコンストラクター内で動的バインディングがこのオブジェクトで機能するかのように、その動作をシミュレートする方法はありますか?。また、DBDIで、基本クラスの構築の一部を派生クラスによって制御/提供する必要があるという特殊なケースについては、私のブログエントリ「パーツファクトリを使用して構築後を回避する方法」を参照してください。
乾杯&hth。、