Menu
CoddyTech

多重継承

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 53/104。

C++では、クラスは複数の基底クラスを同時に継承できます。これは多重継承と呼ばれ、異なるクラス階層の機能を組み合わせることができます。

複数のクラスを継承するには、カンマで区切ります。

class Printer {
public:
    void print() {
        std::cout << "Printing document" << std::endl;
    }
};

class Scanner {
public:
    void scan() {
        std::cout << "Scanning document" << std::endl;
    }
};

class MultiFunctionDevice : public Printer, public Scanner {
public:
    void copy() {
        scan();
        print();
    }
};

MultiFunctionDeviceクラスは、PrinterとScannerの両方のメソッドを利用できるようになりました。

MultiFunctionDevice mfd;
mfd.print();  // Printer 由来
mfd.scan();   // Scanner 由来
mfd.copy();   // 自身のメソッド

コンストラクターは継承宣言に記載された基底クラスの順(左から右)に呼び出され、デストラクターは逆の順に呼び出されます。初期化リストで各基底クラスのコンストラクターに引数を渡すことができます。

class MultiFunctionDevice : public Printer, public Scanner {
public:
    MultiFunctionDevice() : Printer(), Scanner() {}
};

両方の基底クラスに同じ名前のメンバーがある場合、問題が発生する可能性があります。これにより曖昧さが生じるため、どちらを指すのかを指定するにはスコープ解決演算子を使う必要があります。

class A { public: void show() {} };
class B { public: void show() {} };
class C : public A, public B {};

C obj;
obj.A::show();  // Aのバージョンを呼び出す
obj.B::show();  // Bのバージョンを呼び出す

多重継承は強力ですが、特に基底クラスが共通の祖先を持つ場合、複雑な状況につながることがあります。次のレッスンでは、その課題について見ていきます。

challenge icon

チャレンジ

簡単

多重継承を使って、複数の基底クラスの機能を組み合わせたスマートホームデバイスシステムを作りましょう。WiFiに接続でき、音声で操作できるデバイスを作成し、これらの機能を統合したスマートスピーカーにまとめます。

コードを次の3つのファイルに分けて構成します。

  • WiFiDevice.h: ネットワークに接続できるデバイスを表すWiFiDeviceクラスを定義します。
    • protectedなstd::string networkNameメンバー
    • ネットワーク名を受け取り、保存するコンストラクター
    • Connecting to WiFi: <networkName>を出力するpublicなconnect()メソッド
    • WiFi Status: Connectedを出力するpublicなstatus()メソッド
  • VoiceControl.h: 音声機能を備えたデバイスを表すVoiceControlクラスを定義します。
    • protectedなstd::string assistantNameメンバー
    • アシスタント名を受け取り、保存するコンストラクター
    • <assistantName> is listening...を出力するpublicなlisten()メソッド
    • Voice Status: Activeを出力するpublicなstatus()メソッド
  • main.cpp: 3つの入力を読み込みます(それぞれ別の行)。
    1. デバイス名(文字列)
    2. WiFiネットワーク名(文字列)
    3. 音声アシスタント名(文字列)

    WiFiDeviceとVoiceControlの両方をpublic継承するSmartSpeakerクラスを定義します。

    • privateなstd::string deviceNameメンバー
    • 3つすべてのパラメーターを受け取るコンストラクター。初期化リストを使って、ネットワーク名をWiFiDeviceに、アシスタント名をVoiceControlに渡し、デバイス名を保存します。
    • <deviceName> powering on...を出力した後、connect()とlisten()を呼び出すpowerOn()メソッド
    • デバイス名を出力し、スコープ解決演算子を使って両方のstatus()メソッドを呼び出し、曖昧さを解消するshowAllStatus()メソッド

    入力値を使ってSmartSpeakerオブジェクトを作成します。powerOn()を呼び出し、空行を出力してから、showAllStatus()を呼び出します。

たとえば、入力がEcho、HomeNetwork、Alexaの場合:

Echo powering on...
Connecting to WiFi: HomeNetwork
Alexa is listening...

Echo Status:
WiFi Status: Connected
Voice Status: Active

showAllStatus()メソッドは、1行にデバイス名と" Status:"を続けて出力し、その後、両方の基底クラスに同じ名前のメソッドがあるため曖昧さを避ける目的で、WiFiDevice::status()とVoiceControl::status()を使って各基底クラスのstatus()メソッドを呼び出します。

自分で試してみよう

#include <iostream>
#include <string>
#include "WiFiDevice.h"
#include "VoiceControl.h"

using namespace std;

// TODO: WiFiDevice と VoiceControl の両方を public 継承する SmartSpeaker クラスを定義する
// - 非公開メンバー: deviceName (string)
// - コンストラクター: deviceName、networkName、assistantName を受け取る
//   初期化リストを使って networkName を WiFiDevice に、assistantName を VoiceControl に渡す
// - powerOn() メソッド: "<deviceName> powering on..." を出力し、その後 connect() と listen() を呼び出す
// - showAllStatus() メソッド: "<deviceName> Status:" を出力し、その後両方の status() メソッドを呼び出す
//   スコープ解決を使用する(WiFiDevice::status() と VoiceControl::status())

class SmartSpeaker {
    // TODO: ここに SmartSpeaker クラスを実装する
};

int main() {
    string deviceName, networkName, assistantName;
    getline(cin, deviceName);
    getline(cin, networkName);
    getline(cin, assistantName);

    // TODO: 入力値を使って SmartSpeaker オブジェクトを作成する
    // TODO: powerOn() を呼び出す
    // TODO: 空行を出力する
    // TODO: showAllStatus() を呼び出す

    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C++オンラインコンパイラ