继承

基类,派生类,转化切片

继承允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。在派生类中,会额外新建成员变量 ,而不会新建成员函数,但对于静态成员来说,它并不会新建 —— 成员函数被保存到了公共代码区。

继承用法

  1. 派生类中,成员的访问方式取权限较小的那个,并且只允许向上转换——派生类赋值给父类 ,反之则不成立。
  2. 友元关系不能继承。

使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过
最好显示的写出继承方式。

基类private成员在派生类中无论以什么方式继承都是不可见的。如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected

继承后成员访问方式的改变

赋值兼容转换(切片)

发生在派生类赋值给父类的时候,并不会发生类型转换中常现的临时变量,而是直接将派生类当作一种特殊的父类,找到父类需要的部分将其分割出去。

切片的别名,指针

不产生临时对象的情况
其中 p_p1 是 s1 中父类那一部分的别名

1
2
3
4
5
6
7
/*子类对象可以赋值给父类对象/指针/引用*/
Student sobj ;

Person pobj = sobj ;
Person* pp = &sobj;
Person& rp = sobj;
//不产生临时变量

指针同理,如下图中:
继承的指针别名

ptrp指向s中父类的那一部分

基类的指针可以通过强制类型转换赋值给派生类的指针
同样也是向上转换,基类变为派生类,但注意越界访问的问题。

ps2发生了越界

作用域

域:是一种编译器在语法检查阶段的查找规则,查找默认具有就近原则

默认是:局部域,函数域,当前类域
,父类域,全局域。

隐藏/重定义

子类和父类只要有同名成员,子类的成员就会隐藏父类的成员。如果想访问父类成员的话,需要在成员前指定父类域

易出题,如找不到成员函数,可能会编译报错,并且,尽量不要在继承体系当中定义重名成员

初始化

在派生类中,不可以显示的在初始化列表中初始化基类成员

规定:派生类若想要初始化父类的成员,默认情况下会调用父类的默认构造

在初始化列表中,对于内置类型不做处理,自定义类型调用他们的构造函数,而对于基类来说,则是将他们当作一个整体,直接去调用基类的默认构造

自动调用基类的默认构造

如果想要调用People(int id) ,那么就需要如下的方法:people(0)

正确写法

派生类的拷贝构造

派生类调用拷贝构造

实验代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;

class People
{
protected:

People(const People& p)
:_Id(p._Id)
,_weight(p._weight)
{}
People(int id = 0,int weight = 0)
:_Id(id)
,_weight(weight)
{}
protected:
int _Id;
int _weight;
};
class Student: public People
{
public:
Student()
:People(10,10)
,_stuId(10)
{}
Student(const Student& s)
:People(s)
,_stuId(s._stuId)
{}
int _stuId;
};

int main()
{
Student s1;
Student s2(s1);/*拷贝构造*/
//Student s3(s1);/*如果在派生类中没有调用基类的拷贝构造,那会去调用基类的默认构造*/

return 0;
}


核心:基类和派生类各干各的,如果想要在派生类中使用赋值拷贝,那么就在这个过程中使用基类的赋值拷贝。子不能用父,父不能用子

基类和父类关系

例如:

在子类的赋值运算符重载里调用父类的赋值运算符重载

继承的析构函数

不需要显示调用。

由于多态的原因,所有析构函数的函数名都被处理为了destructor,所以在派生类调用基类的析构时,需要指定基类域——但实际上都使用自动调用,用于保证析构顺序——先完成子类析构,再调用父类析构,因为子类中可能使用父类的成员,而父类不会使用子类。

不同与构造函数中,由于父类的声明始终先于子类的成员,所以构造的顺序始终都是先父后子,并且也没有像析构那样自动调用

如何避免继承

  • 将不想被继承的类的构造(析构)函数私有化。并且为了防止无法创建该类的问题,还需要创建一个公有的静态成员函数,用于创建或者释放(static可以解决没有对象却可以调用成员函数的问题)**

  • final:基类加一个final。(C++11)


继承
https://weihehe.top/2023/07/01/二叉树/
作者
weihehe
发布于
2023年7月1日
许可协议