仮想継承

C++ の場合、同じクラスを継承する場合に明示的に virtual 修飾することではじめて仮想継承が有効になる。
クラス A を継承するクラス B と C があって、これらふたつを多重継承するクラス D において、基底クラス A を唯一にしたい…次のような継承関係を実現したい時に virtual キーワードを使う。

   A
  / \
 /   \
B     C
 \   /
  \ /
   D

virtual キーワードを指定する場所がわかりにくいとおもうので、上述の継承木を実現する際のコード断片を次に示す。

#include <iostream>

struct A { int v_a; };
struct B : virtual A { int v_b; };
struct C : virtual A { int v_c; };
struct D : B, C { int v_d; };

int main()
{
  D o;
  std::cout << &static_cast<A&>(o) << ", " << &static_cast<A&>(o).v_a << std::endl;
  std::cout << &static_cast<B&>(o) << ", " << &static_cast<B&>(o).v_a << std::endl;
  std::cout << &static_cast<C&>(o) << ", " << &static_cast<C&>(o).v_a << std::endl;
  std::cout << &static_cast<D&>(o) << ", " << &static_cast<D&>(o).v_a << std::endl;
  return 0;
}

これをコンパイル・リンクして実行すると結果は次のようになる:

> make poly && ./poly
g++ poly.cc -o poly
0x7fff5fbffa80, 0x7fff5fbffa80
0x7fff5fbffa60, 0x7fff5fbffa80
0x7fff5fbffa70, 0x7fff5fbffa80
0x7fff5fbffa60, 0x7fff5fbffa80

D のインスタンス o をそれぞれ A, B, C, D にキャストして、そのオブジェクトとメンバー変数 v_a のアドレスを表示している。どのクラスにキャストしてもメンバー変数 v_a の実体は同じアドレスにある…これが仮想継承である。