栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++虚表与ABI兼容

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++虚表与ABI兼容

虚表生成

C++的类只要有一个虚函数,就会生成一张虚表

class A
{
};

class B
{
public:
	virtual void vfunc1();
}
sizeof(A) = 1	// 空类1个字节用于地址定位
sizeof(B) = 4	// 有虚表指针,占sizeof(void*)字节
子类的虚表

VisualStudio可以使用 cl Test.cpp -d1 reportSingleClassLayoutC 查看内存布局
reportSingleClassLayout<类名>,例如 reportSingleClassLayoutC,是查看类C的布局

class A
{
public:
	virtual void vfunc1();
private:
	int a;
};

class B
{
public:
	virtual void vfunc2();
private:
	int b;
};

class C1 : public A
{
public:
    virtual void vfunc3();
private:
    int c;
};

class C2 : public A, public B
{
public:
    virtual void vfunc3();
private:
    int c;
};

类 C1 的内存布局

class C1        size(12):
        +---
 0      | +--- (base class A)
 0      | | {vfptr}
 4      | | a
        | +---
 8      | c
        +---

C1::$vftable@:
        | &C1_meta
        |  0
 0      | &A::vfunc1
 1      | &C1::vfunc3

类 C2 的内存布局

class C2        size(20):
        +---
 0      | +--- (base class A)
 0      | | {vfptr}
 4      | | a
        | +---
 8      | +--- (base class B)
 8      | | {vfptr}
12      | | b
        | +---
16      | c
        +---

C2::$vftable@A@:
        | &C2_meta
        |  0
 0      | &A::vfunc1
 1      | &C2::vfunc3

C2::$vftable@B@:
        | -8
 0      | &B::vfunc2
C++类虚表中函数顺序规则
  1. 从基类开始,按照申明顺序每遇到一个不是重写的虚函数,就记录在表中
  2. 如果有重载,则提前重载的虚函数
  3. 依次循环遍历子类,如果遇到重写,则替换相应的虚函数
举例
class A
{
public:
	virtual void vfunc1() = 0;
	virtual void vfunc2() = 0;
	virtual void vfunc1(int x) = 0;
	virtual void vfunc3() = 0;
	virtual void vfunc1(int x, int y) = 0;
};

class B : public A
{
public:
	virtual void vfunc1(int x) = 0;
	virtual void vfunc4() = 0;
	virtual void vfunc2(int x) = 0
}

请问B的虚表是应该是什么样的?

  1. 遍历A中的虚函数
void A::vfunc1();

由于 vfunc1 有两个重载,按照第 2 条规则,依次提前重载函数

void A::vfunc1();
void A::vfunc1(int x);
void A::vfunc1(int x, int y);
  1. 继续遍历A中的虚函数
void A::vfunc1();
void A::vfunc1(int x);
void A::vfunc1(int x, int y);
void A::vfunc2();
void A::vfunc3();
  1. 由于 B 重写了 A 的 void vfunc1(int x) 函数,所以将表中对应的函数替换
void A::vfunc1();
void B::vfunc1(int x);
void A::vfunc1(int x, int y);
void A::vfunc2();
void A::vfunc3();
  1. 添加 B::vfunc4() 到虚表中
void A::vfunc1();
void B::vfunc1(int x);
void A::vfunc1(int x, int y);
void A::vfunc2();
void A::vfunc3();
void B::vfunc4();
  1. 由于 B::vfunc2(int x) 没有重写A中的函数,按照规则 1 添加到虚表中
void A::vfunc1();
void B::vfunc1(int x);
void A::vfunc1(int x, int y);
void A::vfunc2();
void A::vfunc3();
void B::vfunc4();
void B::vfunc2(int x);
搞清楚虚表有什么用?

答:ABI兼容

举例

你写了这样一个SDK

  • awesome.h
class IAwesomeSDK
{
public:
	virtual void foo() = 0;
	virtual void bar(int x) = 0;
};

extern "C" {

// 创建SDK实例
IAwesomeSDK *createAwesomeInstance();

// 销毁SDK实例
void destroyAwesomeInstance();

} // extern "C"

调用方使用时一般这么写

  • demo.cpp
int main(int argc, char **argv)
{
	IAwesomeSDK *sdk = createAwesomeInstance();
	sdk->foo();
	sdk->bar();
	destroyAwesomeInstance();
	return 0;
}

如果保证新发布的动态库可以兼容之前的程序(集成DLL的程序不需要重新编译,就可以使用新DLL),那么动态库中添加功能需要注意

  1. 只能在类最后添加新函数
class IAwesomeSDK
{
public:
	virtual void feature1() = 0;		// 错误
	virtual void foo() = 0;
	virtual void bar(int x) = 0;
};
  1. 添加的新函数不可以与旧函数重名(重载)
class IAwesomeSDK
{
public:
	virtual void foo() = 0;
	virtual void bar(int x) = 0;
	virtual void bar() = 0;				// 错误
};
  1. 不可以修改旧函数的签名(参数,返回值,限定符等)
class IAwesomeSDK
{
public:
	virtual void foo(int x = 0) = 0;	// 错误
	virtual void bar(int x) = 0;
};
  1. 不可以重新排序旧函数
class IAwesomeSDK
{
public:
	virtual void bar(int x) = 0;		// 错误
	virtual void foo() = 0;				// 错误
};

这时你要添加一个新功能,还希望旧程序可以不重新编译替换新DLL,你可以这么做

class IAwesomeSDK
{
public:
	virtual void foo() = 0;
	virtual void bar(int x) = 0;
	virtual void feature() = 0;			// 正确
};
导出DLL注意事项
  1. 申请和释放保持在同一模块

最好不要在接口处使用STL库,除非编译器选项一致、STL实现一致、系统平台一致

class IAwesomeSDK
{
public:
	virtual void foo() = 0;
	virtual void bar(int x) = 0;
	virtual std::string feature() = 0;			// 错误,模块内申请,模块外释放
};
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1001567.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号