多态-->接口复用-->同一接口,不同形态。
(1)静多态:编译阶段确定函数的调用
(2)动多态:运行阶段确定函数的调用
(3) 宏多态:预编译阶段确定函数调用
虚函数表(vftable)
RTTI |
偏移 |
虚函数入口地址 |
动多态:
1.虚函数的处理流程:
虚函数在运行阶段确定函数的调用,属于动多态,虚函数的生成:需要函数的入口地址(内存上)
ELF Head |
指令段 |
数据段 |
符号表(存着函数入口地址) |
函数运行的时候只加载只加载指令和数据到内存上
在编译阶段对虚函数进行处理,备份函数入口地址到数据段(.rodata)
虚表(vftable)
RTTI(运行时的类型信息) |
偏移 |
虚函数入口地址 |
2.vfptr和vftable:
基类:
Show(虚)
Printf(虚)
派生类:
Show
Test(虚)
继承层次:基类中如果同名同参的函数是虚函数,派生类中同名同参的函数也是虚函数
派生类中的Show函数和基类中Show的虚函数-->派生类中的Show会变成虚函数。
Base::
Derive:
派生类内存布局向内合并
派生类虚函数表向内合并和覆盖:
3.哪些函数可以变成虚函数?
(1)能取地址
(2)依赖对象:1.普通类成员方法 2.析构函数
4.虚析构:
基类指针指向派生类对象
析构函数设置虚析构
析构函数满足同名覆盖的关系,虽然析构函数不同名。
5.多态的发生时机:
(1).指针调用虚函数
(2).对象完整
6.虚表的写入时机:
构造函数的第一行代码执行之前
7.纯虚函数:
(1)保留接口(2)不能实现
抽象类:不能实例化对象 只能做指针或引用使用
8.多重继承:
(1)一个派生类继承多个基类
菱形继承
9.虚继承
10.内存布局:
1.非虚基类布局优先于基类
2.虚基类的处理上和继承顺序有关
3.虚基类指针合并(内层)
自主内存回收:人为开辟,系统释放
栈:系统开辟 系统释放
堆:人为开辟 人为释放
new和delete管理动态内存时,会出现几个问题:
1.忘记delete内存 2.使用内存已经被delete的对象 3.同一一个内存被delete多次
考虑到内存的分配和对象的初始化是分开的,我们可以将对象的销毁和对象内存的释放分开,C++定义了智能指针。智能指针的行为类似于普通指针,区别是它可以自动释放所指向的内存。
int *p= new int;堆上内存的所有权交给指针管理。
所有权:访问 删除
对象的生成:
1.开辟内存
2.调用构造函数
对象的销毁:
1.调用析构函数(系统)
2.释放内存
栈上的对象指向堆上的内存(new)
C++ 98 auto_ptr
1.所有权唯一,旧智能指针赋给新智能指针,取消旧智能指针的所有权
可能会导致智能指针提前失效 (不能实现共享)
C++ 11 (boost库) unique_ptr shared_ptr weak_ptr <memory>
scope_ptr:
所有权唯一,禁止拷贝和移动赋值等操作转移权限。
shared_ptr(强指针):
允许多个智能指针,指向同一堆内存,实现共享
引用计数:记录该堆内存多少个对象指向,多一个对象指向(+1),少一个对象指向(-1) 最后一个对象销毁释放该内存
智能指针的相互引用(计数++),会导致内存泄漏
weak_ptr(弱指针):
被用来解决强指针的相互引用问题
1。不能单独使用(必须结合shared_ptr)
2.不处理引用计数