Table of Contents

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) { }
};

仮想継承による問題の解決

#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;
}