ここの人々は、フィールドで C++ 抽象基本クラス コンストラクターを何に使用しますか? 私は、データ メンバーも非純粋な仮想メンバーも持たない純粋なインターフェイス クラスについて話しています。
ABC コンストラクターを有用な方法で使用するイディオムを誰かが示すことができますか? それとも、ABC を使用して、空、インライン、および保護されたままのインターフェイスを実装するという性質に固有のものなのでしょうか?
ここの人々は、フィールドで C++ 抽象基本クラス コンストラクターを何に使用しますか? 私は、データ メンバーも非純粋な仮想メンバーも持たない純粋なインターフェイス クラスについて話しています。
ABC コンストラクターを有用な方法で使用するイディオムを誰かが示すことができますか? それとも、ABC を使用して、空、インライン、および保護されたままのインターフェイスを実装するという性質に固有のものなのでしょうか?
ABC コンストラクターを有用な方法で使用するイディオムを誰かが示すことができますか?
以下に例を示しますが、これは不自然で珍しい例です。
これを使用して、すべてのインスタンスのリストを保持できます。
class IFoo
{
private:
//static members to keep a list of all constructed instances
typedef std::set<IFoo*> Set;
static Set s_set;
protected:
//new instance being created
IFoo()
{
s_set.insert(this);
}
public:
//instance being destroyed
virtual ~IFoo()
{
s_set.remove(this);
}
... plus some other static method and/or property
which accesses the set of all instances ...
};
それとも、ABC を使用して、空、インライン、および保護されたままのインターフェイスを実装するという性質に固有のものなのでしょうか?
通常、それらはまったく宣言されていません。それらを宣言する理由はありません:
すべての派生クラスに共通する動作があるとします。外部レジストリに自分自身を登録したり、何かの有効性をチェックしたりします。
この一般的なコードはすべて、基本クラスのコンストラクターに配置でき、派生クラスのそれぞれのコンストラクターから暗黙的に呼び出されます。
注意:「リソースの取得は初期化です」。
ある種のロックメカニズムとして抽象基本クラスを使用することがあります。たとえば、複数のスレッドが単一のリソースを共有する必要があるマルチスレッド環境では、スレッドはリソースを取得する方法としてコンストラクターを使用し、リソースを解放する方法としてデストラクタを使用できます。
void PlayWithPaintBallGun(Target &target)
{
PaintBallGun paintBallGun; // constructor waits until the gun is free,
// then picks it up.
paintBallGun.Aim(target); // Shoot something
paintBallGun.Fire(); //
// Clever! The destructor is automatically
// called when it goes out of scope. So we
// can't forget to put the gun down.
}
ヒューゴ
有用な例はあまり思いつきません。データメンバーのないクラスには状態がないため、何も初期化できません。ただし、コンストラクタ/デストラクタにログを記録させることはできます。たとえば、すべての Visitor オブジェクトの作成/破棄をログに記録するには:
class Visitor {
public:
Visitor() {
std::cout << "Visitor@" << this << " created"
<< std::endl;
}
virtual ~Visitor() {
std::cout << "Visitor@" << this << " destroyed"
<< std::endl;
}
virtual void visitA(A*) = 0;
virtual void visitB(B*) = 0;
// ...
};
抽象基本クラスのコンストラクターを何かに使用するにはどうすればよいでしょうか?
抽象基本クラス B と派生クラス D があるとします。型 D のオブジェクトが作成されると、B のコンストラクターが最初に呼び出されますが、その時点では、オブジェクトは型 B のままです (こちらを参照)。特に、B のコンストラクターの本体から仮想関数を呼び出すと、それらの関数の B 独自の実装が呼び出されます。しかし、B が純粋な抽象クラスの場合、これらの仮想関数は定義されていないため、プログラムはすぐにクラッシュします。
B のコンストラクターが最も派生したクラス (たとえば D の) の仮想関数の実装を呼び出すことを意図していたと思いますよね? D のオブジェクトはまだ完全に構築されていないため、D の仮想関数の実装内から D のメンバー変数にアクセスすると、初期化されていないメモリにアクセスするため、これは一般的に悪い考えです。
通常、メンバーを適切な値に初期化するためだけに使用されます。