質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
インターフェース

インターフェイスという用語はハードウェア・ソフトウェアの両方に使うことができます。 一般的に、インターフェイスは内部処理の詳細を見せないように設定されます。オブジェクト指向プログラミングにおいて、インターフェイスはabstractクラスとして定義されます。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

10813閲覧

インターフェースクラスを仮想継承して実装する理由

JADEN

総合スコア106

インターフェース

インターフェイスという用語はハードウェア・ソフトウェアの両方に使うことができます。 一般的に、インターフェイスは内部処理の詳細を見せないように設定されます。オブジェクト指向プログラミングにおいて、インターフェイスはabstractクラスとして定義されます。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2016/02/07 14:59

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. 意味不明な継承

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

class IIntとclass IDoubleがclass IBaseを仮想継承して、class CNumberも両者を仮想継承すると、クラス図は、図3の様になり?、いまいち理解できません。

図3のような状況にはなりません。CNumberクラスがIInt, IDoubleを仮想継承する/しないにかかわらず、クラス継承図は図2の通りになります。(Chironianさんの回答と同じ)

クラス継承関係におけるvirtualキーワードは、「あるクラス定義からみた全ての基底クラスのうち、virtualキーワード付きで派生した同じクラス型同士を、それぞれ1つの仮想基底にまとめる」働きとなります。

CNumberクラス定義からさかのぼった場合、(virtualを無視すれば)1つのIInt, 1つのIDouble, 2つのIBaseとなりますが(図1)、実際にはvirtual指定によりIBaseが1つにまとめられます(図2)。


実装する際は、仮想継承である必要はないと思うのですが、なぜ仮想継承しているのでしょうか。
試しに、class CNumber : public IInt, public IDoubleとしましたが、動きました。

おっしゃる通り、このケースでは仮想継承する意義がさほどないと思います。実際、よくあるダイアモンド継承の説明では、ここ(public IInt, public IDouble)を仮想継承にはしませんし。

本当の理由は著者に聞かないとわかりませんが、「インターフェースクラス」という扱いをしていることから、あらゆるクラス継承関係上で実体が複数個現れることがないよう、予防的に常にvirtual派生としているのかもしれません。例えばJava言語のinterfaceと同じ扱いとしたいならば、「インターフェースクラス」=無条件にvirtual派生するという設計方針には一定の妥当性があります。

とはいえ、C++はJavaではありませんから、この設計が常にベストかと言われると大いに疑問はあります。少なくとも、仮想継承はメモリ使用量と処理速度に関して追加のオーバーヘッドが発生するため、むやみやたらに使わない方が良いのは確かです。

投稿2016/02/08 07:00

yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

JADEN

2016/02/08 13:52

回答ありがとうございます。
guest

0

こんにちは。

IIntとIDoubleが1つになろうとするわけではないです。
もう1つ別にCNumberExがIIntとIDoubleをvirtual継承し、更にCSuperNumberがCNumberとCNumberExを継承したら、IIntとIDoubleがダイヤモンド継承されてしまいますが、virtualキーワードが付いているのでIIntとIDoubleとIBaseはそれぞれ1つだけ存在するようになると言うことです。

投稿2016/02/07 16:36

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

JADEN

2016/02/08 13:53

回答ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問