1. 类继承(Class Inheritance)
1.1 概述
类继承 是面向对象编程(OOP)中的一个核心概念,允许一个类(派生类)从另一个类(基类)继承属性和行为。通过继承,派生类可以重用基类的代码,并根据需要添加新的成员或重写现有成员。
1.2 语法
1 | class Base { |
1.3 代码示例
1 |
|
1.4 执行结果
1 | Animal eats. |
2. 虚函数(Virtual Functions)
2.1 概述
虚函数 允许派生类重新定义基类中的函数,以实现多态性。在运行时,根据对象的实际类型调用相应的函数版本。
2.2 语法
1 | class Base { |
2.3 代码示例
1 |
|
2.4 执行结果
1 | Drawing a circle. |
3. 纯虚类与抽象基类(Pure Virtual Classes and Abstract Base Classes)
3.1 概述
纯虚函数 是在基类中声明但不提供实现的虚函数。包含至少一个纯虚函数的类称为 抽象基类(Abstract Base Class,ABC)。抽象基类不能被实例化,要求派生类必须实现所有纯虚函数才能被实例化。
3.2 语法
1 | class Base { |
3.3 代码示例
1 |
|
3.4 执行结果
1 | Car engine started. |
4. 继承后的访问控制(Access Control in Inheritance)
4.1 概述
继承时的 访问控制 决定了基类成员在派生类中的可访问性。继承方式主要有三种:public
、protected
和 private
。它们影响继承成员的访问级别。
4.2 语法与影响
- 公有继承(public inheritance):
- 基类的
public
成员在派生类中保持public
。 - 基类的
protected
成员在派生类中保持protected
。 - 基类的
private
成员在派生类中不可访问。
- 基类的
- 保护继承(protected inheritance):
- 基类的
public
和protected
成员在派生类中都变为protected
。
- 基类的
- 私有继承(private inheritance):
- 基类的
public
和protected
成员在派生类中都变为private
。
- 基类的
4.3 代码示例
1 |
|
5. 继承中类的作用域(Scope of Classes in Inheritance)
5.1 概述
在继承关系中,类的作用域决定了成员名称的可见性和访问方式。派生类可以访问基类的成员,根据访问控制的不同,还可能需要使用 作用域解析符 来访问隐藏的成员。
5.2 代码示例
1 |
|
5.3 执行结果
1 | Display from Derived |
6. 构造函数与拷贝控制(Constructors and Copy Control in Inheritance)
6.1 概述
在继承体系中,类的构造函数和拷贝控制函数(拷贝构造函数、拷贝赋值运算符、析构函数)的调用顺序和行为需要注意。基类的构造函数在派生类之前调用,析构函数则在派生类之后调用。
6.2 构造函数的调用顺序
- 基类的 默认构造函数 首先被调用,除非派生类在初始化列表中显式调用其他基类构造函数。
- 派生类的成员按照声明顺序被构造。
- 派生类的构造函数体被执行。
6.3 代码示例
1 |
|
6.4 执行结果
1 | Creating d1: |
7. 容器与继承(Containers and Inheritance)
7.1 概述
C++ 容器(如 std::vector
、std::list
等) 通常存储对象的副本,而非指向对象的指针。因此,当与继承结合使用时,可能导致 切片(Object Slicing) 问题,即仅存储基类部分,丢失派生类特有的信息。为了实现多态性,推荐使用指针或智能指针存储对象。
7.2 切片问题示例
1 |
|
7.3 使用指针避免切片
1 |
|
7.5 智能指针选择
- **
std::unique_ptr
**:- 独占所有权,不可复制,只能移动。
- 适用于明确的单一所有权场景。
- **
std::shared_ptr
**:- 共享所有权,可以被多个指针共享和引用计数。
- 适用于需要多个所有者的场景。
练习题目
1. 简单继承与成员访问
题目:
定义一个基类 Person
,包含以下成员:
私有成员变量:
name
(字符串类型),age
(整数类型)公共成员函数
:
- 构造函数:接受姓名和年龄作为参数并初始化成员变量
displayInfo()
:打印姓名和年龄
然后,定义一个派生类 Student
,继承自 Person
,并添加以下内容:
私有成员变量:
studentID
(字符串类型)公共成员函数
:
- 构造函数:接受姓名、年龄和学号作为参数,并调用基类构造函数初始化姓名和年龄
- 重写
displayInfo()
:除了显示姓名和年龄外,还显示学号
要求:
- 在
main
函数中,创建一个Student
对象,并调用displayInfo()
函数展示信息。
示例输出:
1 | Name: Alice |
2. 虚函数重写与多态性
题目:
定义一个基类 Shape
,包含以下内容:
公共成员函数
:
- 虚函数
draw()
:在基类中实现,输出 “Drawing a generic shape.”
- 虚函数
然后,定义两个派生类 Circle
和 Rectangle
,分别重写 draw()
函数,实现各自的输出:
Circle
的draw()
输出:”Drawing a circle.”Rectangle
的draw()
输出:”Drawing a rectangle.”
要求:
- 在
main
函数中,创建一个Shape
类型的指针数组,包含不同类型的Shape
对象(Circle
和Rectangle
)。 - 遍历数组,调用每个对象的
draw()
函数,验证多态性的实现。
示例输出:
1 | Drawing a circle. |
3. 函数重载与隐藏
题目:
定义一个基类 Calculator
,包含以下公共成员函数:
int add(int a, int b)
:返回两个整数的和double add(double a, double b)
:返回两个浮点数的和
然后,定义一个派生类 AdvancedCalculator
,继承自 Calculator
,并添加以下成员函数:
int add(int a, int b, int c)
:返回三个整数的和
要求:
在
1
main
函数中,创建一个
1
AdvancedCalculator
对象,分别调用以下函数,并观察输出:
add(2, 3)
add(2.5, 3.5)
add(1, 2, 3)
注意:
- 观察派生类中新增的
add
函数是否影响基类中的同名函数。
示例输出:
1 | 5 |
4. 抽象类与纯虚函数
题目:
定义一个抽象基类 Animal
,包含以下内容:
公共纯虚函数
:
void makeSound() const
:纯虚函数,用于发出动物的叫声
然后,定义两个派生类 Dog
和 Cat
,分别实现 makeSound()
函数:
Dog
的makeSound()
输出:”Woof!”Cat
的makeSound()
输出:”Meow!”
要求:
- 在
main
函数中,创建Dog
和Cat
对象的基类指针,并调用makeSound()
函数,展示多态性。
示例输出:
1 | Woof! |
5. 构造函数与析构函数的继承
题目:
定义一个基类 Vehicle
,包含以下内容:
公共成员函数
:
- 构造函数:输出 “Vehicle constructed.”
- 析构函数:输出 “Vehicle destructed.”
然后,定义一个派生类 Car
,继承自 Vehicle
,并添加以下内容:
公共成员函数
:
- 构造函数:输出 “Car constructed.”
- 析构函数:输出 “Car destructed.”
要求:
- 在
main
函数中,创建一个Car
对象,并观察构造和析构的调用顺序。
示例输出:
1 | Vehicle constructed. |