C++继承
前言
本节内容,将会用到前面类的相关知识以及C++基础教程以及C++类&对象,需要你具备前面的知识,如果你还有不会的或者说不熟悉的地方,请重新温习一下
C++ 继承
继承是面向对象编程中一个非常重要的概念。通过继承,一个类(称为派生类)可以直接使用另一个类(称为基类)的属性和方法,而无需重新编写。这种方式不仅能重用代码,还能让程序更易扩展和维护。
什么是继承?
基类和派生类:
- 基类:已有的类,其属性和方法可以被其他类继承。
- 派生类:继承自基类的类,它可以拥有基类的所有公开和保护成员,同时还可以定义自己的成员。
继承的核心思想:
- 基类定义了一些通用的功能或特性。
- 派生类可以直接使用这些功能,同时根据需要添加新的功能或特性。
继承的现实类比
继承可以看作是“是一种(is-a)关系”。例如:
- 哺乳动物是一种动物。
- 狗是一种哺乳动物。
- 因此,狗也是一种动物。
这种逻辑反映在代码中,可以通过继承轻松实现:
继承的语法
1 | // 定义基类(父类) |
代码解析:
基类 Animal:
- 包含了通用的方法
eat()和sleep(),它们适用于所有的动物。
- 包含了通用的方法
派生类 Dog:
- 通过
: public Animal继承了Animal类的所有公开成员。 - 在
Dog类中添加了一个新的方法bark(),用来描述狗特有的行为。
- 通过
使用派生类对象:
- 派生类对象既可以使用自己的方法,也可以使用从基类继承的方法。
实例:
1 |
|
输出结果:
1 | 动物正在吃东西。 |
继承的细节
访问权限控制:
- 使用
public继承时,基类的public成员仍然是派生类的public成员。 - 使用
private继承时,基类的成员即使是public,在派生类中也会变成private。
- 使用
is-a 关系的本质:
- 派生类对象可以看作是基类对象的一种。例如:
1
2Animal* animal = new Dog();
animal->eat(); // 可以通过基类指针调用基类的方法
- 派生类对象可以看作是基类对象的一种。例如:
重载与扩展:
- 派生类可以覆盖基类的方法,提供更具体的实现。
小总结
- 继承是为了实现代码复用和逻辑组织。
- 基类提供通用功能,派生类可以直接使用这些功能,同时扩展自己特有的功能。
- 继承建立的是一种“是一种(is-a)”的关系,比如“狗是一种动物”。
类的继承详解:基类与派生类
在编程中,一个类可以从其他类继承,这种机制让我们可以复用代码并增强类的功能。继承关系中,被继承的类称为“基类”,继承的类称为“派生类”。
定义派生类
派生类继承基类的数据和函数。定义派生类的格式如下:
1 | class 派生类名: 访问修饰符 基类名 { |
关键点:
- 访问修饰符(
public、protected或private):控制基类成员在派生类中的访问权限。 - 默认访问修饰符:如果没有写访问修饰符,默认是
private。
一个例子:Shape 和 Rectangle
假设我们有一个表示形状的基类 Shape,它可以设置宽度和高度;然后,我们定义一个 Rectangle 类继承自 Shape,并添加计算面积的功能。
代码示例:
1 |
|
运行结果:
1 | Total area: 35 |
访问权限与继承规则
成员访问权限:
基类的成员根据访问修饰符分为三类:public、protected 和 private。这会影响派生类和外部类能否访问这些成员。
| 访问范围 | public | protected | private |
|---|---|---|---|
| 同一个类 | 可以 | 可以 | 可以 |
| 派生类 | 可以 | 可以 | 不可以 |
| 外部类 | 可以 | 不可以 | 不可以 |
注意:
private成员只能在基类内部访问,派生类和外部类无法访问。protected成员可以被派生类访问,但不能被外部类直接访问。public成员任何地方都可以访问。
访问修饰符对派生类的影响:
基类的访问修饰符在派生类中继承的访问权限,取决于派生类的定义方式:
| 派生方式 | 基类 public 成员 | 基类 protected 成员 | 基类 private 成员 |
|---|---|---|---|
public |
保持 public | 保持 protected | 不可访问 |
protected |
降为 protected | 保持 protected | 不可访问 |
private |
降为 private | 降为 private | 不可访问 |
特殊情况:派生类中不能继承的内容
即使派生类继承了基类的大部分内容,但以下几种特殊情况除外:
- 基类的构造函数、析构函数和拷贝构造函数:这些函数不能被派生类直接继承。
- 基类的运算符重载函数:例如,重载的
operator+,派生类不会直接继承。 - 基类的友元函数:友元函数只对声明它们的类开放,不会被派生类直接继承。
小结
- 继承让代码复用更高效:基类定义通用的功能,派生类在此基础上扩展。
- 控制访问权限:通过访问修饰符确保数据的安全性。
- 继承有例外:构造函数等特殊成员无法继承,需要在派生类中重新定义。
这个机制强大而灵活,是面向对象编程的重要特性!
继承类型
想象一下,我们有一个家族,基类就像是家族中的长辈,而派生类则是晚辈。长辈的财产和技能可以传给晚辈,但是传给的方式不同,晚辈对这些财产和技能的拥有和使用方式也会有所不同。
公有继承(public):
- 这就像是长辈公开宣布:“我所有的财产和技能,我的孩子们都可以自由使用。”在这种情况下,如果一个类(我们称之为子类)是从另一个公开的类(基类)继承来的,那么基类中所有公开的成员(比如财产和技能)在子类中也是公开的,可以被外界直接访问。同时,基类中的保护成员(比如一些只有家族内部才能使用的技能)在子类中也保持保护状态,只能被家族内部(也就是子类及其派生类)访问。
保护继承(protected):
- 这就像是长辈说:“我有一些财产和技能,只允许我的孩子们使用,外人不能直接使用,但我的孩子们可以自由地使用。”在保护继承中,基类中的公开和保护成员都会变成子类的保护成员。这意味着这些成员不能被外界直接访问,但是可以在子类及其派生类中被访问。
私有继承(private):
- 这就像是长辈说:“我有一些东西,只留给我的孩子们,而且他们也只能自己使用,不能给外人用,也不能让他们的孩子(也就是孙子辈)使用。”在私有继承中,基类中的公开和保护成员都会变成子类的私有成员。这意味着这些成员只能在子类内部使用,不能被外界或子类的派生类访问。
总结一下,继承类型决定了基类的成员在派生类中的可见性和可访问性。公有继承让基类的成员在派生类中保持原有的访问级别;保护继承将基类的成员都变为派生类的保护成员;私有继承则将基类的成员变为派生类的私有成员。在实际编程中,公有继承是最常用的,因为它允许派生类最大程度地利用基类的功能,同时也保持了灵活性。
多继承
什么是多继承?
多继承指的是一个子类可以同时继承多个父类,从而获得这些父类的属性和方法。在 C++ 中,允许通过多继承来创建更强大的类。这种特性可以通过以下语法实现:
1 | class <派生类名>:<继承方式1> <基类名1>, <继承方式2> <基类名2>, … |
其中:
- 继承方式可以是
public、protected或private,它决定了从父类继承过来的成员在子类中的访问权限。 - 基类名是父类的名字。
- 多个父类之间用逗号分隔。
一个简单的例子
假设我们要设计一个程序,涉及计算矩形的面积,并估算将矩形涂上油漆的总花费。这种情况下,可以通过多继承实现如下功能:
- **一个基类
Shape**:用来保存矩形的宽度和高度,并提供设置宽高的方法。 - **另一个基类
PaintCost**:用来计算油漆的花费。 - **派生类
Rectangle**:同时继承自Shape和PaintCost,可以直接使用这两个基类的功能,并添加自己的功能,比如计算面积。
代码如下:
1 |
|
程序运行的结果
当运行上述代码时,会输出以下内容:
1 | Total area: 35 |
详细解释代码的逻辑
Shape类的功能:- 它包含两个成员变量:
width和height,分别表示矩形的宽度和高度。 - 提供了两个公共方法:
setWidth(int w)和setHeight(int h),用来设置宽度和高度的值。
- 它包含两个成员变量:
PaintCost类的功能:- 包含一个方法
getCost(int area),它接受面积作为参数,并返回涂上油漆的总费用。 - 每平方米油漆的费用为
$70。
- 包含一个方法
Rectangle类的功能:- 它继承了
Shape和PaintCost,因此可以直接使用Shape类的方法(如setWidth和setHeight),以及PaintCost类的方法(如getCost)。 - 它还定义了一个自己的方法
getArea(),用来计算矩形的面积。
- 它继承了
main()函数的执行流程:- 创建一个
Rectangle对象Rect。 - 调用
setWidth(5)和setHeight(7),设置矩形的宽度为 5、高度为 7。 - 调用
getArea()方法,计算矩形的面积为 ( 5 \times 7 = 35 )。 - 调用
getCost(area),计算油漆费用为 ( 35 \times 70 = 2450 )。 - 最终输出面积和总费用。
- 创建一个
为什么多继承很有用?
在本例中,通过继承 Shape 和 PaintCost,Rectangle 类不需要重新定义宽度、高度的管理方法或油漆费用的计算逻辑,这样可以减少代码的重复,同时增加了代码的可读性和可维护性。这种功能组合的方式是多继承的一个典型应用场景。








