James McNellisの答え「Foo<T>
のコンストラクタからecho()
を呼び出すことはできません」は、であり、ほぼです。
Foo<T>
コンストラクタの本体がFoo<T>
のオブジェクトを実行している間に、Foo<T>
コンストラクタから仮想的に呼び出すことはできません。派生クラスパートはまだありません。 echo()
の仮想呼び出しは、コード内でのように、純粋な仮想関数bang、deadに移動します。
ただし、はecho()
のような純粋仮想関数の実装を提供することができ、その後、Foo
コンストラクタから、Foo::echo()
のような、非事実上それを呼び出します。 :-)それ以外はFoo
の実装を呼び出します。あなたは派生クラスの実装を呼びたいと思うのですが。今すぐあなたの問題について
:私はこれはあなたの(不正な)コードを書いているように、
"I'd really like that function in the constructor."
さて、次のようになります。
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
実装を呼び出すようにします。
これを行うにはいくつかの方法があります。彼らはすべて、派生クラスの実装についての知識を基底クラスに持ち込むことに関するものです。
一つは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);
}
あなたはこれら二つのプログラムを勉強すれば、あなたはおそらく、実行対時間をコンパイルするのに加えて、微妙な違いを(注意しましょう時間知識移転)。
最後に、ダーティー・キャストを含むソリューションがあります。また、メンバー・ポインターを使用して、キャストなしで保護された基本クラスの状態にアクセスできるC++タイプ・システムに抜け穴があります。前者は危険であり、後者は不明瞭であり、おそらく非効率的である。だから、しないでください。
しかし、うまくいけば、上記の解決策の1つがあなたに合っているか、または適切な適応策になるでしょう。
ああ、ところで、あなたはのインスタンスであるように思わ問題のより一般的なセットは、DBDI、動的初期化中にバインディングとして知られています。 C++ FAQの23.6 Okay, but is there a way to simulate that behavior as if dynamic binding worked on the this object within my base class's constructor?に、より一般的な扱いがあります。また、派生クラスによって基本クラス構築の一部を制御/提供するDBDIがある特別なケースについては、私のブログエントリ"How to avoid post-construction by using Parts Factories"を参照してください。
乾杯& HTH。、
私はあなたを-1'dか分からないが、あなたのコメントは右私に読み込みます。 G ++は次の警告を出力します: 'warning:abstract virtual 'void Foo :: echo()[T = int]'がコンストラクタから呼び出されました' ...そしてエラー: 'test.cpp :(。text._ZN3FooIiEC2Ei [ Foo :: Foo(int)] + 0x2c): 'Foo :: echo() ''への未定義の参照 –
Ashe
ディスパージングトーンは不要かもしれませんが、この回答は正しいので、私はそれをアップヴォーグしています。言葉の価値があるかもしれません - 基本的に、Barのコンストラクタがオブジェクト作成時にFooのコンストラクタを呼び出すとき、FooはBarについて何も知らない。オブジェクトが完全に作成されてからRTTIが起動し、適切な仮想関数を呼び出すことはできません。 – rcv