继承的好处:
1、可以做代码的复用
2、在基类中给所有派生类提供统一的虚函数接口,让派生类进行重写,然后就可以使用多态了
一:继承的本质和原理
继承的本质:a.代码的复用
b.类和类直接的关系:
组合:a part of ~ ~的一部分
继承:a kind of ~ ~的一种
继承方式 | 基类的访问限定 | 派生类的访问限定 | 外部访问 |
---|---|---|---|
public | public | public | Y |
protected | protected | N | |
private | 被继承但不可见 | N | |
protected | public | protected | N |
protected | protected | N | |
private | 被继承但不可见 | N | |
private | public | private | N |
protected | private | N | |
private | 被继承但不可见 | N |
总结:
- 外部只能访问对象public的成员,protected和private的成员无法直接访问
- 再继承结构中,派生类从基类可以继承private的成员,但派生类无法直接访问
- protected和private的区别?在基类中定义的成员,想被派生类访问,但不想被外部访问,那么在基类中把相关成员定义成protected;如果派生类和外部都不打算访问,那么在基类中,就把相关成员定义成private的
默认的继承方式
class定义派生类,默认继承方式是private
struct定义派生类,默认继承方式是public
二:派生类的构造过程
派生类对象构造和析构的过程是:
1.派生类调用基类的构造函数,初始化从基类继承来的成员
2.调用派生类自己的构造函数,初始化派生类自己特有的成员
....派生类对象的作用域到期→
3.调用派生类的析构函数,释放派生类成员可能占用的外部资源(堆内存,文件)
4.调用基类的析构函数,释放派生类内存中,于从基类继承来的成员可能占用的外部资源(堆内存,文件)
派生类怎么初始化从基类的成员变量?
1 派生类从继承可以继承来所有的成员变量(变量和方法),除了构造函数和析构函数
ans:通过调用相应的构造函数
派生类的构造函数和析构函数,复杂初始化和清理派生类部分
派生类从基类继承来的成员的初始化和清理由基类的构造函数和析构函数来负责
三:重载、隐藏、覆盖
1.重载关系
一组函数要重载,必须处在同一个作用域当中;而且函数名字相同,参数列表不同(本质是根据参数来决定调用哪个函数)
2.隐藏(作用域的隐藏)的关系
在继承结构当中,派生类的同名成员,把基类的同名成员给隐藏调用了(即对函数选择的优先级)
3.覆盖:
基类和派生类的方法,返回值、函数名以及参数列表都相同,而且基类的方法是虚函数,那么派生类的方法就自动处理成虚函数,它们之间成为覆盖关系(本质是根据发起调用的对象来决定调用哪个函数)
基类对象(上)→派生类对象(下)
派生类对象→基类对象
基类指针(引用)→派生类对象
派生类指针(引用)→基类对象
虚函数,静态绑定和动态绑定
类添加了虚函数,对这个类有什么影响?
总结一:
一个类里面定义了虚函数,那么编译阶段,编译器给这个类类型产生一个唯一的vftable虚函数表,虚函数表中主要存储的内容就是RTTI指针和虚函数的地址。当程序运行时,每一张虚函数表都会加载到内存的.rodata区。
总结二:
一个类里面定义了虚函数,那么这个类定义的对象,其运行时,内存中开始部分,多存储一个vfptr虚函数指针,指向相应类型的虚函数表vftable。一个类型定义的n个对象,它们的额vfpt指向的都是同一张虚函数表
总结三:
一个类里面虚函数的个数,不影响对象内存大小(vfptr),影响的是虚函数表的大小
总结四:
如果派生类中的方法,和基类继承来的某个方法,返回值、函数名、参数列表都相同而且基类的方法是virtual/虚函数,那么派生类的这个方法,自动处理成虚函数重写↔覆盖
/*
pb->BaseBase:show //如果发现show是普通函数,就进行静态绑定call Base:show
pb->Base Base:show //如果发现show是虚函数,就进行动态绑定了
mov eax,dword ptr[pb]
movecx,dword ptr[eax]
call ecx // (虚函数的地址)动态(运行时期)的绑定(函数的调用)
*/
pb->show(); //静态绑定调用 call base::show
哪些函数不能实现成虚函数
虚函数依赖:
1.虚函数能产生地址,存储在vftable中
2.对象必须存在 虚函数表指针在对象内存中
构造函数调用时对象还未存在,故其无法成为虚函数
构造函数中调用虚函数,也不会发生动态绑定
派生类构造过程:先调用基类的构造函数→调用派生类的构造函数
是不是虚函数的调用一定就是动态绑定?
在类的构造函数中,调用虚函数,也是静态绑定(构造函数中调用其他函数(虚),不会发生动态绑定)
必须由指针(或者引用)调用虚函数才会发生动态绑定
网友评论