【C++基础知识】《深度探索C++对象模型》 笔记
Inside the c++ Object Model
1. 关于对象的继承
表格驱动模型
虚拟多重继承
struct是否可以在一些时候替代class?在C++里,否
string是一种OB类型,而非OO类型,其特点是速度更快,在编译的时候已经解析完毕
子类赋值给基类造成的切割
2. 构造函数语义学
explicit关键字在C++中的引入
default constructor
vtbl:虚函数表
vptr:虚函数表指针,编译器在class object中引入的一个指针,指向vtbl(虚函数表)
编译器合成的default constructor不会初始化基本类型
2.2 Copy Constructor的建构操作
返回值,函数参数,赋值会调用Copy Constructor
default constructor和copy constructor不是一定会由编译器产生的,而是在必要的时候(即初始化和copy构造)才会构造出来
Memberwise Semantics 基于成员的(拷贝)语义
Bitwise Semantics 不要使用这种拷贝
如何处理继承关系中含有virtual的类的copy constructor以实现安全拷贝
如何处理继承关系中包含了virtual base class的copy constructor
2.3 程序转化语意学
编译器怎么实现参数拷贝, 一种NRV的方式可以提高效率,但是可能造成跟我们的目的不同的操作,比如两次调用拷贝构造
explicit Point3D() 关键字explicit可以阻止copy constructor的调用,但是有些时候没必要:只涉及数值,而非地址
有些时候必要:含有虚函数的类,在没有explicit的时候会有memcpy,这个时候会导致类的虚函数表被破坏
2.4 成员们的初始化列表
initialization list:
A(): [ i(a), j(b) ] 类的构造的下划线部分是initialization list
3. Data语意学
Data Member的绑定
类的内容在继承的时候可能会因为编译器而增加很多大小。
类里的typedef 应该放在类里的开头,因为对类是按顺序编译的
3.2 Data Member的布局
非静态的member data才会进入布局,再加上vptr
隐含的this指针对数据的存储作用
3.3 Data Member的存取
static与非static
3.4“继承”与Data Member
就是非虚的一般继承,很简单了
只继承
本来的指针A指向了Base, class A: public Base
我们想用virtual function实现多态,但是如果两个A指针内互相赋值(B->A=>*A->*A)就可能导致本来的成员因为切割消失了
继承+多态
编译器对vptr位置的设定:可前可后
多重继承
按照继承顺序布局,会加上自己的vptr和继承来的
虚拟继承
从iostream作为例子,istream和ostream都继承了ios
3.5 对象成员的效率
主要通过测试查看效率,发现编译器的实现不是很聪明。(没开优化的情况下)
3.6 Data Members的指针
4.Function 语意学
4.1 Member 的各种调用方式
non-static成员函数的效率跟nonmember function要保持相近,但不是提高nonmember效率而是因为non-staitc成员函数降低了效率:转换成mangling过的函数
mangling的做法是不统一的,但是最后产生的函数名必须是不同的,即使函数是同名重载的;链接器使用的是经过mangle的名称,而编译器不是,所以报错信息有时候很奇怪
x(type1 x1) -> x_Point5_type1
static member function
static member function基本同于nonmember function,因此可以可以用于多线程编程
4.2 Vritual Member Function
5. Construction,Destruction and Copy构造、析构、拷贝
所有赋值应该只在构造函数,否则会破坏封装性,使得维护困难(一种规范)
纯虚函数
纯虚函数可被调用(虽然无意义)
析构函数一般是虚函数,否则会导致派生类内存泄露
5.1 无继承下的构造函数
指针的赋值不会触发构造函数,按照copy by value,左边得到的只是Plain OI Data。
为继承做准备
衡量虚函数表的效率
NRV优化(函数返回值和等号只创建了一个对象)
5.2 继承体系下的对象构造
编译器的扩充代码
Line b = a; 会合成implicit copy constructor
a = b; 会合成implicit copy assignment operator
1. 虚继承
object和suboject
2. vptr
因为我们可能希望构造函数能返回基类的值,所以构造函数及构造函数内部都不能调用虚函数,但是这样会造成限制
3.拷贝语意(operator=)
拷贝语意与bitwise copy的选择
建议不要在任何虚基类中声明数据,否则会难以维护
4.测试
5.解构语意学
默认情况下没有destructor,而不是默认有
析构的顺序;虚析构函数的意义(已经前述)
6. 执行期语意学
6.1. 对象的构造和析构
为了减少构造消耗,尽量随用随声明变量(而不是全放在开头)
不同类型数据的构造和析构选择
全局对象(bss段)
局部静态对象
对象数组:
A values[10];会依次调用A(), 如果只写了带参数的A(int a),那么就会插入A()
6.2 new和delete运算符
另外考虑new T[0];虽然合法,但是不是想要的语意(NULL),它返回一个字节大小的空间
delete 一个基类指针表示的数组的时候,只会调用基类的析构,而derived类不会调用析构函数
placement operator new(标准C++不支持):
new (arean) Derived; 构造Derived对象放到指针arean
6.3 临时性对象
等号运算符
加号运算符
三目运算符
7. 站在对象模型的类端
Template,Exception Handling,Runtime Type Identification(RTTI)
Template |
应用:属性混合(内存配置机制),互斥机制, 1.编译器的出错信息检查过程: lexical analyzer parser 2.类型决议 3.链接时的具现化
|
Exception Handling |
可以看C++11的auto_ptr和shared_ptr, 跟new,delete有关的内存配置exception 对Exception Handling的支持
|
RTTI |
执行期类型识别 保证安全的向下转型downcast RTTI对多态类型的类型识别支持 dynamic_cast
|
弹性 |
dynamically shared libraries shared memory distributed objects
|
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通