在“继承简介”课程中,我们曾指出:使用派生类的最大优势之一在于能够复用已编写完成的代码。你可以继承基类的功能,随后添加新的功能、修改既有功能,或隐藏不需要的功能。在接下来的几课中,我们将逐一详细探讨这些操作的具体实现方式。
首先,给出一个简单的基类示例:
#include <iostream>
class Base
{
protected:
int m_value {};
public:
Base(int value)
: m_value { value }
{
}
void identify() const { std::cout << "I am a Base\n"; }
};
接下来,创建一个从 Base 公有继承的派生类。由于我们希望在构造派生类对象时能够设定 m_value 的值,故在派生类构造函数的初始化列表中显式调用基类构造函数:
class Derived: public Base
{
public:
Derived(int value)
: Base { value }
{
}
};
在派生类中添加新功能
在上述示例中,由于我们拥有 Base 类的源码,因此如有需要,可直接向 Base 类添加功能。
然而,实际开发中常会遇到以下情形:
- 虽然拥有基类源码,但并不想修改它。例如,你从第三方供应商处购买了一套代码库,却需要额外功能。若直接修改原代码,一旦供应商发布更新,你的改动要么被覆盖,要么必须手动迁移——既耗时又易出错。
- 甚至根本无法修改基类。例如,标准库中的代码我们无法改动,但可以从这些类派生,再向派生类添加所需功能。对于仅提供头文件、实现已预编译的第三方库亦同理。
无论哪种情况,最佳做法都是派生出自定义类,并在派生类中添加所需功能。
Base 类中明显缺失的是让外部访问 m_value 的手段。我们本可在 Base 类中增加一个访问函数,但为示例起见,将其添加至派生类。由于 m_value 在 Base 中被声明为 protected,派生类可直接访问。
要向派生类添加新功能,只需像平常一样在派生类中声明即可:
class Derived: public Base
{
public:
Derived(int value)
: Base { value }
{
}
int getValue() const { return m_value; }
};
现在,外部代码便可通过 Derived 对象调用 getValue() 以获取 m_value 的值:
int main()
{
Derived derived { 5 };
std::cout << "derived has value " << derived.getValue() << '\n';
return 0;
}
运行结果:
derived has value 5
需要明确指出的是,Base 类型的对象无法使用派生类中的 getValue() 函数。下述代码无法通过编译:
int main()
{
Base base { 5 };
std::cout << "base has value " << base.getValue() << '\n';
return 0;
}
> 原因在于 Base 类中并无 getValue() 成员函数;该函数属于 Derived。Derived 是一种 Base,因此 Derived 可访问 Base 的成员;但 Base 却无法访问 Derived 的任何成员。