方法重写
本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 51 课,共 104 课。
方法重写是指派生类为基类中已有的方法提供自己的实现。这样,派生类就能在保留相同方法签名的同时,自定义继承来的行为。
要重写方法,只需在派生类中定义一个方法,并确保名称、返回类型和参数完全相同:
class Animal {
public:
void speak() {
std::cout << "Some sound" << std::endl;
}
};
class Dog : public Animal {
public:
void speak() {
std::cout << "Woof!" << std::endl;
}
};
Dog d;
d.speak(); // 输出:Woof!派生类版本会隐藏基类版本。不过,你仍然可以使用作用域解析运算符访问基类方法:
class Dog : public Animal {
public:
void speak() {
Animal::speak(); // 调用基类中的版本
std::cout << "Woof!" << std::endl;
}
};这种基本的重写方式有一个重要限制。通过基类指针或引用访问派生类对象时,调用的是基类版本:
Dog d;
Animal* ptr = &d;
ptr->speak(); // 输出:Some sound(不是 Woof!)这是因为编译器根据指针类型而不是实际对象类型来确定要调用哪个方法。要实现真正的运行时多态,让程序根据实际对象调用正确的方法,你需要使用虚函数,我们会在下一课中介绍它们。
挑战
简单我们来构建一个通知系统,演示方法重写的实际效果。你将创建一个基类 Notifier,以及两个自定义消息发送方式的专用通知类。
你将把代码分成 3 个文件:
Notifier.h:定义一个基类Notifier,其中包含:- 一个受保护的
std::string recipient成员 - 一个接收收件人姓名并保存该姓名的构造函数
- 一个公共
send(const std::string& message)方法,用于打印:Sending to <recipient>: <message>
- 一个受保护的
EmailNotifier.h:定义一个公共继承自Notifier的EmailNotifier类:- 一个接收收件人并将其传递给基类的构造函数
- 重写
send()方法,先使用Notifier::send()调用基类版本,然后打印:[Email sent successfully]
main.cpp:读取两项输入(每项各占一行):- 收件人姓名(字符串)
- 消息内容(字符串)
在 main.cpp 中直接定义一个公共继承自
Notifier的SMSNotifier类:- 一个接收收件人并将其传递给基类的构造函数
- 重写
send()方法,打印:SMS to <recipient>: <message>(完全替换基类行为,不调用基类方法)
使用相同的收件人,分别创建一个基类
Notifier对象、一个EmailNotifier对象和一个SMSNotifier对象。对每个对象调用send()并传入输入的消息,每次调用之间打印一条分隔线:--- Base Notifier --- <output> --- Email Notifier --- <output> --- SMS Notifier --- <output>
例如,输入 Alice 和 Hello there! 时:
--- Base Notifier ---
Sending to Alice: Hello there!
--- Email Notifier ---
Sending to Alice: Hello there!
[Email sent successfully]
--- SMS Notifier ---
SMS to Alice: Hello there!注意,EmailNotifier 会先调用父类方法来扩展基类行为,而 SMSNotifier 则会用自己的实现完全替换基类行为。别忘了添加头文件保护,并在每个文件中包含相应的头文件。
亲手试试
#include <iostream>
#include <string>
#include "Notifier.h"
#include "EmailNotifier.h"
using namespace std;
// TODO:在这里定义 SMSNotifier 类,公开继承 Notifier
// 构造函数将 recipient 传给基类
// 重写 send(),输出:SMS to <recipient>: <message>
// (完全替换基类的行为,不要调用父类的 send())
int main() {
string recipient;
string message;
getline(cin, recipient);
getline(cin, message);
// TODO:用 recipient 创建 Notifier 对象
// 输出 "--- Base Notifier ---"
// 将 message 传给 send()
// TODO:用 recipient 创建 EmailNotifier 对象
// 输出 "--- Email Notifier ---"
// 将 message 传给 send()
// TODO:用 recipient 创建 SMSNotifier 对象
// 输出 "--- SMS Notifier ---"
// 将 message 传给 send()
return 0;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C++ 在线编译器