43項 多重継承は慎重に使おう
多重継承は慎重に使おう
多重継承を使うと、名前衝突により問題が起こることがあります。
あいまいな状態になるときは、
①同名の関数を複数継承したとき、関数を個別に再定義できない問題
②1つのクラスを複数の経路で継承してしまうとき、名前解決があいまいになる問題
があります。
本項には上記2つの場合の解決策が挙げられていますが、できる限り多重継承は避けるべきです。
①同名の関数を複数継承したとき、関数を個別に再定義できない問題
下のコードのような状態です。
class Lottery { public: virtual void draw(); }; class GraphicalObject { public: virtual void draw(); }; class LotterySimulation : public Lottery, public GraphicalObject { public: virtual void draw(); //呼び出したポインタの型によって、 //Lottery::draw()とGraphicalObject::draw()を //使い分けたいが、無理 }; LotterySimulation *pls = new LotterySimulation; Lottery *pl = new LotterySimulation; GraphicalObject *pg = new LotterySimulation; pls->draw(); //LotterySimulation::draw() pl->draw(); //LotterySimulation::draw() pg->draw(); //LotterySimulation::draw()
本書で挙げられている解決策は、新しいクラスを追加することです。
class Lottery { public: virtual void draw();//1,この関数が呼び出されると、 }; class AuxLottery : public Lottery { public: virtual void lotteryDraw() = 0;//3,2の関数で呼び出されたこの関数も、仮想関数テーブルをたどり・・・ virtual void draw(){ lotteryDraw(); }//2,仮想関数テーブルをたどり、この関数が呼び出される }; class GraphicalObject { public: virtual void draw(); }; class AuxGraphicalObject : public GraphicalObject { public: virtual void graphicalObjectDraw() = 0; virtual void draw(){ graphicalObjectDraw(); } }; class LotterySimulation : public AuxLottery, public AuxGraphicalObject { public: virtual void lotteryDraw();//4,この関数が呼び出される。この関数には、Lottery::Draw()を上書きした処理をさせる。 virtual void graphicalObjectDraw(); }; Lottery *pl = new LotterySimulation; GraphicalObject *pg = new LotterySimulation; pl->draw(); //LotterySimulation::lotteryDraw() pg->draw(); //LotterySimulation::graphicalObjectDraw()
②1つのクラスを複数の経路で多重に継承してしまうとき、名前解決があいまいになる問題
下のような状態です
class A { public: virtual void func(); }; class B : public A { }; class C : public A { }; class D :public B, public C { }; D d; d.func(); //あいまい
virtual継承によって解決します。
class A { public: virtual void func(); }; class B : virtual public A //virtual継承 Aをひとつにする { }; class C : virtual public A { }; class D :public B, public C { };
最後に
本書にも書かれていますが、できる限り多重継承は避けるべきです。