web-dev-qa-db-ja.com

デフォルトのコンストラクターが仮想継承で呼び出されるのはなぜですか?

次のコードでdaughter型のオブジェクトをインスタンス化すると、デフォルトのgrandmother()コンストラクターが呼び出される理由がわかりません。

grandmother(int)コンストラクターを(私のmotherクラスコンストラクターの仕様に従うために)呼び出すか、仮想継承のためにこのコードをまったくコンパイルすべきではないと考えました。

ここでは、コンパイラーはgrandmotherデフォルトコンストラクターを黙って呼び出しますが、私はそれを要求しませんでした。

#include <iostream>

class grandmother {
public:
    grandmother() {
        std::cout << "grandmother (default)" << std::endl;
    }
    grandmother(int attr) {
        std::cout << "grandmother: " << attr << std::endl;
    }
};

class mother: virtual public grandmother {
public:
    mother(int attr) : grandmother(attr) {
        std::cout << "mother: " << attr << std::endl;
    }
};

class daughter: virtual public mother {
public:
    daughter(int attr) : mother(attr) {
        std::cout << "daughter: " << attr << std::endl;
    }
};

int main() {
  daughter x(0);
}
71
Simon Desfarges

仮想継承を使用する場合、仮想ベースクラスのコンストラクターは、最も派生したクラスのコンストラクターによって直接呼び出されます。この場合、daughterコンストラクターはgrandmotherコンストラクターを直接呼び出します。

初期化リストでgrandmotherコンストラクターを明示的に呼び出していないため、デフォルトのコンストラクターが呼び出されます。正しいコンストラクターを呼び出すには、次のように変更します。

daugther(int attr) : grandmother(attr), mother(attr) { ... }

This FAQ entry も参照してください。

76
interjay