1.继承的概念
继承,是面向对象的三大特性之一。继承可以理解成是类级别的一个复用,它允许我们在原有类的基础上进行扩展,增加新的功能。
当创建一个类时,我们可以继承一个已有类的成员和方法,并且在原有的基础上进行提升,这个被继承的类叫做基类,而这个继承后新建的类叫做派生类。
用法如下:
class [派生类名] : [继承类型] [基类名]
例如:
1 2 3 4 5 6 7 8 9 10 11 |
|
这里的派生类Student就复用了Person的方法和成员,并在此基础上扩展补充。
2.继承方式
继承的方式和类的访问限定符一样,分为public(公有继承),private(私有继承), protected(保护继承)三种。
不同的继承方式,在派生类中继承下来的基类成员的访问权限也不一样。
基类的其他成员在子类的访问方式 = Min(成员在基类的访问限定符,继承方式)
备注:
1.在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能 在派生类的类里面使用,实际中扩展维护性不强。
2.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
3.基类与派生类的赋值转换
派生类可以赋值给基类的对象、指针或者引用,这样的赋值也叫做对象切割。
例如上面的Person类和Student类
这种赋值只能是派生类赋给基类(但需要割掉多出来的成员例如_ stuID),而基类对象不能赋给派生类。
基类的指针可以强制类型转换赋值给派生类的指针, 如:
1 2 3 4 5 6 7 8 9 10 |
|
小结:
1.派生类可以赋值给基类的对象、指针或者引用
2.基类对象不能赋值给派生类对象
3.基类的指针可以通过强制类型转换赋值给派生类的指针。**🍁但是必须是基类的指针是指向派生类对象时才是安全的,否则会存在越界的风险。**这里基类如果是多态类型,可以使用RTT的dynamic_cast来进行识别后进行安全转换。
4.作用域与隐藏
🎄隐藏:隐藏,也叫做重定义,当基类和派生类中出现重名的成员时,派生类就会将基类的同名成员给隐藏起来,然后使用自己的。(但是隐藏并不意味着就无法访问,可以通过指明基类作用域来显式访问隐藏成员。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
例如这里的f( )就构成了隐藏
同时,这里还有个需要注意的问题,在基类与派生类中,同名的方法并不能构成重载,因为处于不同的作用域中。而只要满足方法名相同,就会构成隐藏。
5.派生类的默认成员函数
在每一个类中,都会有6个默认的成员函数,这些函数即使我们自己不去实现,编译器也会帮我们实现。
🎄这里有两点需要注意(笔试题常考):
1.构造函数,拷贝构造,operator=三种情况,都要调用父类对应的构造函数/拷贝构造/operator=进行对父类的成员变量的初始化,并且倘若父类没有默认的构造函数的时候(比如父类写了带参的构造函数),我们就要显式调用(Person(参数…),Person::operator=(参数…))
🍁构造函数显示调用
派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函 数,则必须在派生类构造函数的初始化列表阶段显示调用。
1 2 3 4 5 |
|
🍁拷贝构造显示调用
建议拷贝构造都用显示调用,不然免不了出现子类拷贝构造当中调用了父类的构造函数的情况(因为拷贝构造也是构造,在初始化列表处,对于子类而言,父类相当于一个自定义类型对象,子类会调用父类的构造函数对父类的资源进行初始化。)
1 2 3 4 5 |
|
🍁派生类的operator=必须要调用基类的operator=完成基类的复制。
1 2 3 4 5 6 7 8 |
|
🍁析构函数
由于编译器会将析构函数的名字处理成destructor,因此派生类和基类的析构函数会构成隐藏关系,故若要派生类要调用基类的析构函数,那么需要显式调用,但是编译器会默认在派生类的析构函数调用结束后调用基类的析构函数,这样就析构两次了。
1 2 3 4 5 6 7 8 9 |
|
在派生类中,基类的析构函数会被隐藏,虽然它们这里的名字不同,但是为了实现多态, 它们都会被编译器重命名为destructor。在调用子类的构造函数时,我们是先调用父类的构造函数,后对子类的成员进行构造。由先构造后析构的顺序,所以我们是在析构函数当中析构子类的资源,析构函数调用完后编译器自动帮我们调用父类的析构函数。
6.友元与静态成员
🍁1.友元
友元关系是不会继承的,如果子类要使用父类的友元,则子类自己也要将其定义为友元。
🍁2.静态成员
基类定义了static静态成员,无论继承了多少次,派生了多少子类,静态成员在这整个继承体系中有且只有一个。静态成员不再单独属于某一个类亦或者是某一个对象,而是属于这一整个继承体系。
7.菱形继承与虚继承
首先简单介绍下单继承、多继承的概念
单继承:一个子类只有一个直接父类时称这个继承关系为单继承
多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
菱形继承:菱形继承是多继承的一种特殊情况,下面简单举例介绍下菱形继承及其带来的二义性问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
哦豁!!!菱形继承这个关系感受到了吧!!!