可以扩展虚拟接口而无需重新编译客户端代码吗?

Bas*_*evs 8 c++ virtual-functions shared-libraries binary-compatibility

库提供具有虚函数的类.是否可以使用新的虚函数扩展此类,而无需重新编译动态链接到库的二进制文件?

我相信这在标准中是不可能的.有平台允许吗?

如果只将新函数添加到类主体的末尾,那会更容易吗?

Mat*_* M. 5

该标准不涉及二进制兼容性.它关注的是类,并且通过将类的定义从一个转换单元"更改"到另一个转换单元,您确实会调用未定义的行为.

大多数编译器确实允许进行大量更改而无需重新编译,但是列表很小......对于这个,我会说这可能是不可能的,这取决于派生类的先验知识.

我预见到的问题在于编译器通常在虚拟表上执行的优化.

当您使用虚函数创建一个类时,您将得到一个如下所示的虚拟表:

// B virtual table
0 - Offset to complete object
1 - RTTI
2 - func0
3 - func1
...
Run Code Online (Sandbox Code Playgroud)

为了获得一些空间,派生类自己的虚函数通常是"附加"的:

// D virtual table
Same as B
N+3 - func(N+1)
N+4 - func(N+2)
Run Code Online (Sandbox Code Playgroud)

这样一个D对象只有一个虚拟指针,即使该类型是(静态地)B(通过指针或引用),也可以这样使用.

但是,如果你在B没有重新编译的情况下进行扩展D,那么它就会崩溃,因为当你调用N+1函数时,B你会调用N+1函数,D甚至可能没有相同的参数...... oups!

但是,如果你知道的话,没有派生类添加任何自己的虚函数.

  • 请注意,有些库在末尾添加了几个虚拟虚函数(通常称为`reserved1`,`reserved2`等),因此可以在不破坏二进制兼容性的情况下替换它们. (2认同)