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 又能通过语音控制的设备,然后把这些功能整合到一个智能音箱中。

你需要将代码分成三个文件:

  • WiFiDevice.h:定义一个 WiFiDevice 类,用于表示能够连接到网络的设备:
    • 一个受保护的 std::string networkName 成员
    • 一个接收网络名称并保存该名称的构造函数
    • 一个公共 connect() 方法,用于打印:Connecting to WiFi: <networkName>
    • 一个公共 status() 方法,用于打印:WiFi Status: Connected
  • VoiceControl.h:定义一个 VoiceControl 类,用于表示具有语音功能的设备:
    • 一个受保护的 std::string assistantName 成员
    • 一个接收语音助手名称并保存该名称的构造函数
    • 一个公共 listen() 方法,用于打印:<assistantName> is listening...
    • 一个公共 status() 方法,用于打印:Voice Status: Active
  • main.cpp:读取三个输入(每个输入单独占一行):
    1. 设备名称(字符串)
    2. WiFi 网络名称(字符串)
    3. 语音助手名称(字符串)

    定义一个 SmartSpeaker 类,使其以公共方式同时继承 WiFiDevice 和 VoiceControl:

    • 一个私有的 std::string deviceName 成员
    • 一个接收全部三个参数的构造函数,使用初始化列表将网络名称传递给 WiFiDevice,将语音助手名称传递给 VoiceControl,并保存设备名称
    • 一个 powerOn() 方法,用于打印:<deviceName> powering on...,然后调用 connect() 和 listen()
    • 一个 showAllStatus() 方法,用于打印设备名称,然后使用作用域解析运算符调用两个 status() 方法,以解决歧义

    使用输入值创建一个 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() 方法应在一行中打印设备名称,后面跟着 " Status:",然后分别使用 WiFiDevice::status() 和 VoiceControl::status() 调用每个基类的 status() 方法,以避免歧义,因为两个基类都有同名的方法。

亲手试试

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

using namespace std;

// TODO: 定义 SmartSpeaker 类,公开继承 WiFiDevice 和 VoiceControl
// 私有成员: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++ 在线编译器