C++におけるダイアモンド継承
実現方法
#include <iostream>
class X {
public:
X(int id) : id_{id} { }
int id() const noexcept { return id_; }
private:
int id_;
};
class Ya : public X {
public:
Ya() : X(0) { }
};
class Yb : public X {
public:
Yb() : X(1) { }
};
class Z : public Ya, public Yb {
public:
Z() { }
};
int main() {
Z z;
// std::cout << z.id() << std::endl; // error: 'id' is ambiguous
std::cout << static_cast<Ya&>(z).id() << std::endl; // = 0
std::cout << static_cast<Yb&>(z).id() << std::endl; // = 1
return 0;
}
注意点
ZからXのメンバに直接アクセスできない
z.id() // error: 'id' is ambiguous
static_cast<Ya&>(z).id() // ok
static_cast<Yb&>(z).id() // ok
ZがXを継承してもXにアクセスできない
// warning: direct base 'X' inaccessible in 'Z' due to ambiguity
class Z : public X, public Ya, public Yb {
public:
Z() : X(2) { }
};
仮想継承による問題の解決
virtual
キーワードを使って基底Xを仮想継承をすることで,Zのインスタンスに関わる基底Xのインスタンスを唯一とすることができる
基底Xの唯一のインスタンスのコンストラクタは,Xを仮想継承したクラスを直接的あるいは間接的に継承しているクラスの全てから呼ばれなければならない
YaあるいはYbのどちらか一方のみで仮想継承をすると,YaとYbのみを継承するZから,Xにアクセスすることはできない
#include <iostream>
class X {
public:
X(int id) : id_{id} { }
int id() const noexcept { return id_; }
private:
int id_;
};
class Ya : virtual public X {
public:
Ya() : X(0) { }
};
class Yb : virtual public X {
public:
Yb() : X(1) { }
};
class Z : public Ya, public Yb {
public:
Z() : X(2) { }
};
class W : public Z {
public:
W() : X(3) { }
};
int main() {
Z z;
std::cout << z.id() << std::endl; // = 2
std::cout << static_cast<Ya&>(z).id() << std::endl; // = 2
std::cout << static_cast<Yb&>(z).id() << std::endl; // = 2
W w;
std::cout << w.id() << std::endl; // = 3
std::cout << static_cast<Ya&>(w).id() << std::endl; // = 3
std::cout << static_cast<Yb&>(w).id() << std::endl; // = 3
std::cout << static_cast<Z &>(w).id() << std::endl; // = 3
return 0;
}