多重继承
本课属于 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 的版本多重继承功能强大,但可能导致复杂的情况,尤其是当基类有共同的祖先类时。我们会在下一课中探讨这个挑战。
挑战
简单我们来构建一个智能家居设备系统,通过多重继承组合多个基类的功能。你将创建既能连接 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:读取三个输入(每个输入单独占一行):- 设备名称(字符串)
- WiFi 网络名称(字符串)
- 语音助手名称(字符串)
定义一个
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: ActiveshowAllStatus() 方法应在一行中打印设备名称,后面跟着 " 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;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C++ 在线编译器