C++の教科書(ロベールのC++入門講座p655)で、インターフェースクラスを仮想継承して実装していました。
実装する際は、仮想継承である必要はないと思うのですが、なぜ仮想継承しているのでしょうか。
試しに、class CNumber : public IInt, public IDoubleとしましたが、動きました。
class IIntとclass IDoubleがclass IBaseを仮想継承している理由は分かります。
仮想継承でないと、class CNumberからのGetStringメンバ関数の呼び出しがあいまいになるからです。
(恐らく、インターフェースクラスに共通のインターフェースを与えるために、class IBaseを仮想継承しているのだと思います)
C++
1#include <iostream> 2#include <string> 3 4class IBase { 5public: 6 virtual ~IBase() {} 7 virtual std::string GetString() const = 0; 8}; 9 10class IInt : public virtual IBase { 11public: 12 virtual int GetInt() const = 0; 13}; 14 15class IDouble : public virtual IBase { 16public: 17 virtual double GetDouble() const = 0; 18}; 19 20class CNumber : public virtual IInt, public virtual IDouble { 21public: 22 CNumber(int intData, double doubleData) : m_int(intData), m_double(doubleData) { 23 } 24 std::string GetString() const { 25 return std::string("CNumber"); 26 } 27 int GetInt() const { 28 return m_int; 29 } 30 double GetDouble() const { 31 return m_double; 32 } 33 34private: 35 int m_int; 36 double m_double; 37}; 38 39int main() { 40 CNumber cnumber(2, 3.0); 41 42 IBase& ibase = cnumber; 43 std::cout << ibase.GetString() << std::endl; 44 45 IInt& iint = cnumber; 46 std::cout << iint.GetString() << std::endl; 47 std::cout << iint.GetInt() << std::endl; 48 49 IDouble& idouble = cnumber; 50 std::cout << idouble.GetString() << std::endl; 51 std::cout << idouble.GetDouble() << std::endl; 52}
そもそも、仮想継承はダイヤモンド継承を作るために行うものだと思うので、class IIntとclass IDoubleをclass CNumberが仮想継承すると、クラス図が書けなくなるのではないでしょうか。
以下に、その理由を説明します。
class IIntとclass IDoubleがclass IBaseを仮想継承せず、class CNumberも両者を仮想継承しなければ、クラス図は、図1です。
図1. 多重継承
class IIntとclass IDoubleがclass IBaseを仮想継承して、class CNumberは両者を仮想継承しなければ、クラス図は図2です。
図2. ダイヤモンド継承
class IIntとclass IDoubleがclass IBaseを仮想継承して、class CNumberも両者を仮想継承すると、クラス図は、図3の様になり?、いまいち理解できません。
図3. 意味不明な継承
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/02/08 13:52