C++二进制兼容问题
C++对象的内存布局规则:
- 非静态数据成员被配置于每一个对象实例(class object)之内,(偏移地址寻址),静态数据成员被存放在所有的对象实例之外(.data节)。
- 静态和非静态的方法成员也存放在所有的对象实例之外(.text节)。(符号寻址)
- 虚方法virtural function以两个步骤支持
a. 每一个类class产生出一堆指向virtual functions的指针,存放在表格中,称为virtual table (vtbl)
b. 每一个对象实例被添加了一个指针,指向相关的virtual table。这个指针通常称为vptr。Vptr的设定和重置由每一个类的构造器,析构器,赋值运算符自动完成。每一个类所关联的type_info object也经由virtural table 指出,通常放在表格的第一个slot处。
visual studio cl 查看类布局
首先启动cmd.exe:VS2015 -> Tools -> Visual Studio Command Prompt
查看单个类布局,例:
cl -d1reportSingleClassLayoutBase D:\VSWorkspace\test\test\test.cpp
命令会列出类名中包含“Base”的类的布局。
查看所有类布局,例:
cl -d1reportAllClassLayout D:\VSWorkspace\test\test\test.cpp
小结:
- 非静态成员变量和虚函数通过相对于类实例的首地址偏移量来访问
- 虚函数不导出,用户无法继承;
- 虚函数表里的函数指针在编译时已定;
- inline函数导出将不再内联,在运行时依赖动态库;不导出在编译时直接展开,不依赖动态库;
- 静态成员函数、静态成员变量和非内联非虚函数必须导出,在运行时依赖符号表与动态库建立联系;
二进制兼容技巧
- 不要给已有的方法增加参数,可以为该函数增加新的重载
- 不使用虚函数作为接口