在共享库中定义抽象接口 class
Defining interface of abstract class in shared library
假设我有一个抽象基 class 定义如下:
interface.hpp
#ifndef INTERFACE_HPP
#define INTERFACE_HPP 1
class interface{
public:
virtual void func() = 0;
};
#endif // INTERFACE_HPP
然后我把一个翻译单元test.cpp
编译成一个共享对象test.so
:
test.cpp
#include "interface.hpp"
#include <iostream>
class test_interface: public interface{
public:
void func(){std::cout << "test_interface::func() called\n";}
};
extern "C"
interface &get_interface(){
static test_interface test;
return test;
}
如果我在可执行文件中打开该共享对象并尝试像这样调用 get_interface
:
#include <dlfcn.h>
#include "interface.hpp"
int main(){
void *handle = dlopen("test.so", RTLD_LAZY);
void *func = dlsym(handle, "get_interface");
interface &i = reinterpret_cast<interface &(*)()>(func)();
i.func(); // print "test_interface::func() called"
dlclose(handle);
}
(假装我做了错误检查)
行为是否明确?或者我是在踩自己的脚趾,假设这总是有效的吗?
记住我只会使用 clang 和 gcc
一个问题是您希望 protected: ~interface()
阻止客户删除 interface
。
第二个实际问题是,如果您修改 interface
,请记住仅在 class 的 末尾 添加方法,然后执行不添加新的虚拟覆盖(具有相同名称的函数)。 (在实践中,我看到覆盖被聚集在一起,即使它们没有聚集在头文件中)。
如果您不仅需要一个接口(例如,您的接口继承自其他 2 个接口),请使用 virtual
继承。根据我的经验,事实证明添加新的 virtual
parents 也是有问题的。
None 由 C++ 标准定义,该标准与二进制接口和 运行 代码加载时间无关。然而,以上是我使用类似技术的经验(诚然,使用指针而不是引用,使用 MSVC 而不是 gcc/clang)。
您必须跟踪您使用的编译器上的 ABI。如果您通过此类接口传递 std
结构,请注意它们有时会更改布局(例如,gcc 中的 std::string
从引用计数变为不计数,或者 std::list
得到 O(1) size
),并且它们不太可能在编译器之间 layout-compatible(好吧,标准库,不同的编译器默认情况下倾向于使用不同的库)。
假设我有一个抽象基 class 定义如下:
interface.hpp
#ifndef INTERFACE_HPP
#define INTERFACE_HPP 1
class interface{
public:
virtual void func() = 0;
};
#endif // INTERFACE_HPP
然后我把一个翻译单元test.cpp
编译成一个共享对象test.so
:
test.cpp
#include "interface.hpp"
#include <iostream>
class test_interface: public interface{
public:
void func(){std::cout << "test_interface::func() called\n";}
};
extern "C"
interface &get_interface(){
static test_interface test;
return test;
}
如果我在可执行文件中打开该共享对象并尝试像这样调用 get_interface
:
#include <dlfcn.h>
#include "interface.hpp"
int main(){
void *handle = dlopen("test.so", RTLD_LAZY);
void *func = dlsym(handle, "get_interface");
interface &i = reinterpret_cast<interface &(*)()>(func)();
i.func(); // print "test_interface::func() called"
dlclose(handle);
}
(假装我做了错误检查)
行为是否明确?或者我是在踩自己的脚趾,假设这总是有效的吗?
记住我只会使用 clang 和 gcc
一个问题是您希望 protected: ~interface()
阻止客户删除 interface
。
第二个实际问题是,如果您修改 interface
,请记住仅在 class 的 末尾 添加方法,然后执行不添加新的虚拟覆盖(具有相同名称的函数)。 (在实践中,我看到覆盖被聚集在一起,即使它们没有聚集在头文件中)。
如果您不仅需要一个接口(例如,您的接口继承自其他 2 个接口),请使用 virtual
继承。根据我的经验,事实证明添加新的 virtual
parents 也是有问题的。
None 由 C++ 标准定义,该标准与二进制接口和 运行 代码加载时间无关。然而,以上是我使用类似技术的经验(诚然,使用指针而不是引用,使用 MSVC 而不是 gcc/clang)。
您必须跟踪您使用的编译器上的 ABI。如果您通过此类接口传递 std
结构,请注意它们有时会更改布局(例如,gcc 中的 std::string
从引用计数变为不计数,或者 std::list
得到 O(1) size
),并且它们不太可能在编译器之间 layout-compatible(好吧,标准库,不同的编译器默认情况下倾向于使用不同的库)。