【cpp进阶-04】C++的底层实现细节
CPP底层细节
面向对象
类与对象
类在编译时不占用内存空间,只是对象的模板。
对象创建时在栈或堆分配内存。
成员变量与成员函数

成员变量分别存储在堆或栈中;成员函数(编译时经过名字编码为对象无关的全局函数,传入this指针)共享内存。
-
静态变量
静态成员变量存储在静态区,类的对象共享。
静态成员函数存储在代码区,但不传入this指针。
构造函数
-
自动生成
用户未定义构造函数,编译器自动生成默认构造函数;用户定义构造函数后,编译器不再自动生成。
-
初始化列表:对象类型,const类型,引用类型必须初始化构造。
step1:分配内存空间
step2:初始化成员变量
step3:调用构造方法实现体
析构函数
对象类型会自动调用,指针类型需要delete调用。
三大特性
继承
-
虚函数
-
成员变量:
若含有虚函数表指针 _vptr,虚函数表指针→基类变量→派生类变量
若不含虚函数表指针_vptr,基类变量→派生类变量。
-
成员函数:
case 普通函数: 根据指针的类型,调用指针类的函数。 case 虚函数: 通过指针指向的对象的虚函数表找到函数,根据指针指向对象的类调用函数。 注意点: 派生类无法重载基类,同名遮蔽。 初始化列表不能写继承变量,需要借助基类的构造函数初始化。
-
构造函数与析构函数
构造前未初始化虚函数表,构造函数不能设置为虚函数。
析构函数设置为虚函数,防止内存泄漏。
-
-
多继承:内存模型如下
-
虚继承
非虚继承存在二义性,重复定义的问题,虚继承用于解决菱形继承的问题。
实现:例如A->B1,B2->C
B1,B2分别保存A的虚基类指针,则C在取变量时不存在二义性。
多态
-
介绍
静态多态:编译时多态,重载、模板实现。
动态多态:运行时多态,虚函数。
内存模型小结
若无虚函数,虚继承->普通对象内存模型
含有虚函数->增加虚函数表
含有虚继承->增加虚基类表
-
模板与泛型
-
编译器的自动类型推导
-
两次编译:声明处对模板编译,调用处参数替换后编译
-
优势:提高复用性;编译时检查,安全性高
-
-
RTTI(Run-Time Type Identification)
typeid运算符:返回表达式或类型的实际类型。
dynamic_cast运算符:将基类指针转化为派生类指针。
虚函数表中存放type_info来判断类型,上述运算符会通过查虚函数表获取类型。
强类型语言
类型转化
static_cast
静态转化,编译时进行,异常抛出编译时错误。
一般说良性转化,风险度低。
const_cast
去掉表达式中的volatile和const修饰符
volatile:多线程使用,每次从内存中读取数据,保证不被修改。
reinterpret_cast
仅对二进制位重新解释,不会根据规则转化,风险较大
dynamic_cast
继承层次之间的转化
向上转化无条件;向下转化需要RTTI机制辅助。
STL
容器
- vector:数组;支持快速随机访问
- list:双向链表;支持快速删除插入
- deque:指针数组+多个缓冲区;支持首位插入删除,快速随机访问
- set/map:红黑树;有序,不可重复
- multiset/multimap:红黑树;有序,可重复
- hashset/hashmap:hash表,无序,不可重复
适配器
- stack:list 或 deque实现,不用vector是扩容耗时。
- queue:list 或 deque实现,不用vector是扩容耗时。
- priority_queue:vector+heap
扩容机制
每次以2倍或1.5倍扩容,g++2倍,MSVC是1.5倍。每次扩容在堆上开辟新空间。