一.继承
概念
继承就是在一个已存在的类的基础上,建立一个新的类。并拥有其特性。
已存在的类称为基类或者父类
新类称为派生类或者子类
差异化
我们创建子类的目的,是在父类的基础上改变其部分特性或者增加新特性
- 修改继承来的基类内容
- 属性:1、公有属性可以直接改。更改后基类的属性也会改变,因为改的是同一份变量。私有属性,需要使用基类的公有函数进行更改。
- 函数:函数隐藏,通过派生类实现一个同名同参数的函数,来隐藏基类的函数
- 新增派生类的内容
这里需要注意函数重载和函数隐藏,函数重载的同名不同参,可以同时使用两个函数,函数隐藏同名同参数 想要调用父类被隐藏的函数需要加作用域父类名::
构造函数
子类继承了父类,但是不继承父类的构造函数与析构函数.但是子类会默认调用父类的无参构造函数,
存在问题:当我们父类中不写无参构造函数,但是写了有参构造函数,编译器不会自动添加无参构造函数,所以子类也就没办法赋值了,因为父类中没有无参构造函数,也不会默认调用有参构造函数
解决方案
1.手写无参构造函数
2.手动调用父类的有参构造函数
2.1透传构造
Son():Father(参数){}
2.2委托构造
一个类的构造函数可以调用这个类的另一个构造函数,但是要避免循环委托。
委托构造的性能要低于透传构造,但是代码的维护性“更好”。因为通常一个类中构造函数都会委托给能力最强(参数最多)的构造函数,在代码重构时,只需要更改这个能力最强的构造函数即可。
2.3继承构造
C++11 新增的写法,只需要一句话,就可以自动给派生类添加n(n为基类构造函数的个数(不包含默认无参构造函数))个构造函数。并且每个派生类的构造函数的格式都与基类相同,每个派生类的构造函数都通过透传构造调用对应格式的基类构造函数。
using Father::Father;
对象的创建和销毁流程
- 在创建的过程中,同类型的内存区域,基类先开辟。对象创建:(先基类后派生类)。对象销毁(先派生类,后基类)。
- 静态的创建早于非静态。
多重继承
C++支持多重继承,即一个派生类可以有多个基类。派生类对于每个基类的关系仍然可以看作是一个单继承。
class 子类 :public 父类1,public 父类2
{
public:
};
可能出现的问题
1.重名问题即一个子类继承不同父类中含有同名成员
当多个基类具有重名成员时,编译器在编译的过程中会出现二义性的问题。
解决方案: 子类.父类名::函数名/参数表明哪一个父类的
2.菱形继承
一个子类继承多个父类,且父类继承同一个父类.
当出现虚继承时,家具厂类会生成一张虚基类表。这个表并不会占用任何对象的存储空间,属于家具厂类持有,在程序启动时加载进内存,表中记录了家具厂类的函数的调用地址偏移量。Bed和Sofa对象会出现一个隐藏的成员变量指针,指向Furniture类中的虚基类表,占用对象四个字节。SofaBed继承Sofa和Bed时,SofaBed类对象会同时拥有两个虚基类表指针成员,在调用时通过查表解决二义性。
虚继承使用关键字:virtual
#include <iostream>
using namespace std;
// 家具厂
class Furniture
{
public:
void func()
{
cout << "家具厂里有家具" << endl;
}
};
class Sofa:virtual public Furniture
{
public:
};
class Bed:virtual public Furniture
{
public:
};
// 多重继承
class SofaBed :public Sofa,public Bed
{
public:
};
int main()
{
SofaBed sb;
sb.func();
return 0;
}
二.继承权限
1.权限修饰符
公有权限:public,在此权限下类内类外都能调用
私有权限:private,只能类内调用,类外需要使用专门的函数接口调用
保护权限:protected
类内 | 派生类中 | 全局 | |
private | √ | × | × |
protected | √ | √ | × |
public | √ | √ | √ |