クラスDにC1とC2を多重継承したことにより,
同じ名前のメソッドid()(C1::id()とC2::id()の2つ)が取り込まれてしまっている.
class C1 {
public:
    int id() { return 1; };
};
class C2 {
public:
    int id() { return 2; };
};
class D : public C1, public C2 {
};
これにより,次のメソッド呼び出しがあいまいになり,コンパイル時エラーとなる.
D obj; cout << obj.id() << endl;
このような場合には,次のように修飾することでC1::id()とC2::id()のいずれを呼び出せばよいかを明示する必要がある.
D obj; cout << obj.C1::id() << endl; cout << obj.C2::id() << endl;
class Base {
public:
    virtual int id() { return 1; }
};
class C1 : public Base { };
class C2 : public Base { };
class D : public C1, public C2 { };
前のパターンとの違いは,
まったく同じメソッドid()がC1経由とC2経由の2系統でDに継承されていること.
同じものなんだからイイじゃんと思えてくるんだけども,ダメらしくて,次のコードはコンパイル時エラーになってしまう.
D obj; cout << obj.id() << endl;
この場合もどちら経由で継承したメソッドを使うかを明示する方法
(obj.C1::id(),obj.C2::id()またはobj.Base::id()と明示する方法)が使えるけど,
このメソッドの実装は共通の祖先Baseにあって同じものなのだから違和感がある.
そこでC++では仮想基本クラス(virtual base class)という考え方が導入されている.
class Base {
public:
    virtual int id() { return 1; }
};
class C1 : public virtual Base { };
class C2 : public virtual Base { };
class D : public C1, public C2 { };
このようにvirtualをつけて継承しておけば,Baseは仮想基本クラスと解釈され,obj.id()と呼び出してよくなる.
D obj; cout << obj.id() << endl;
クラス自体を仮想基本クラスと定義するのではなく(Baseの定義でvirtual class Base { ... };とするのではなく),
継承するときに“仮想基本クラスとして継承する”ことをコンパイラに指示するというモデルになっていることに注意.
仮想基本クラスというモノがあるわけではなく,あくまで継承の一形態であるということを理解しておかないと混乱する.
そのため,“仮想基本クラス”(virtual base class)という用語のかわりに
“仮想継承”(virtual inheritance)という語もよく使われている.
virtualはC1とC2両方のクラス定義についていないとダメ.obj.Base::id()とかobj.C1::id()のように明示的に修飾して呼び出してもよい.
    ただ,このように明示する方法は
    それが単にあいまいさを回避するためのものだったのか,
    あるいは他の実装ではなくまさにその指定した実装を使う必要があったのかがわからなくなって,
    基本クラス側の構成がかわったときなどに困る原因になりそうだ.
    特に意味がないのであれば仮想基本クラスとして継承することで あいまいさを回避して,呼び出しはシンプルにobj.id()としたい.