说我有三个库,都是用C ++编写的:logging.a
:用于帮助记录的静态库。它定义了一个抽象类,其他类可使用该抽象类来自定义其日志记录(通过实现纯虚拟方法virtual void CustomLogger::customLogging(std::string) = 0
)。libmainproject.so
:主库。它包含一个对外界未知的类(CustomLoggerImpl
),该类扩展了CustomLogger
并实现了自定义日志记录方法。libplugin.so
:一个插件库,需要记录内容,并希望将其日志记录与libmainproject
中的记录集成。
尽管两个库的内部都是用C ++编写的,但libmainproject
和libplugin
之间的接口是C接口。libplugin
不知道CustomLoggerImpl
内部是否存在libmainproject
,但确实从CustomLogger
了解接口logging
。
为了使用来自libplugin
的自定义日志记录,我已将CustomLoggerImpl
的指针传递为void *
(因为它是通过C接口发生的,因此无法使用自定义对象)。
一旦需要登录插件,就将void *
(指向CustomLoggerImpl
对象)转换为CustomLogger *
(Liskov替换原理)。然后,我调用customLogger->customLogging("whatever");
。
尽管没有崩溃,但呼叫似乎未成功进入libmainproject
。这是为什么?我认为问题在于vtable存在一些问题,因此它无法从没有对象定义的其他二进制文件中正常工作,但希望对此有更深入的解释正在发生。
最佳答案
动态链接(共享)库不是由Standard C ++定义的,因此您处于特定于实现的行为中。
实现通常做合理的事情;可以合理地假设CustomLogger
在所有二进制文件中都具有相同的vtable
布局。标准甚至没有规定vtable,因此这不是一个硬性声明。
支持动态链接库的实现通常不假定所有代码都位于单个二进制文件中。在Windows上,MSVC进行了较少的假设,因为它具有__declspec(dllimport)
扩展名,该扩展名告诉编译器特定的代码来自另一个二进制文件。但是您的问题明确表明您没有使用MSVC。您的编译器不会仅仅因为customLogging
调用libplugin.so
就假定必须在libplugin.so
中定义customLogging
替代。
因此,我将同意VTT。这里最大的问题似乎是您要通过CustomLoggerImpl*
将CustomLogger*
强制转换为void*
,CustomLoggerImpl* -> CustomLogger* -> void* -> CustomLogger*
。转换为基类应该在C ++代码中显式进行。
关于c++ - 如果使用非公共(public)类,则vtable是否在二进制文件之间持久存在?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58801578/