由于我们不应该跨插件边界传递除普通旧数据结构[1]之外的任何其他内容,因此我想出了以下想法来传递对象:
- 公开插件“C”接口中的所有公共方法,并在应用程序端将插件包装在一个对象中。 (参见以下示例)
我的问题是:有一个更好的方法吗 ?
[编辑] 请参阅下面我的编辑,其中使用标准布局对象可能是更好的解决方案。
这是一个说明这个想法的玩具示例:
我想跨越边界传递一个 Writer :
class Writer{
Writer();
virtual void write(std::string) = 0;
~Writer(){}
};
但是,我们知道由于兼容性问题,不应该直接这样做。
这个想法是将 Writer 的接口公开为插件中的免费函数:
// plugin
extern "C"{
Writer* create_writer(){
return new PluginWriterImpl{};
}
void write(Writer* this_ , const char* str){
this_->write(std::string{str});
}
void delete_writer(Writer* this_){
delete this_;
}
}
并将所有这些函数调用包装在应用程序端的包装对象中:
// app
class WriterWrapper : public Writer{
private:
Writer* the_plugin_writer; //object being wrapped
public:
WriterWrapper() : the_plugin_writer{ create_writer() }
{}
void write(std::string str) override{
write(the_plugin_writer, str.c_str() );
}
~WriterWrapper(){
delete_writer(the_plugin_writer);
}
};
这导致了很多转发功能。除了 POD 之外没有其他东西可以跨越边界,并且应用程序不知道当前 Writer 的实现来自插件这一事实。
[1] 对于二进制兼容性问题。欲了解更多信息,你可以看到这个相关的SO问题:c++ 插件:可以传递多态对象吗?
[编辑] 看来我们可以跨越边界传递标准布局。如果是这样,这样的解决方案是否正确? (可以简化吗?)
我们想要跨越边界传递 Writer :
class Writer{
Writer();
virtual void write(std::string) = 0;
~Writer(){}
};
因此,我们将从插件中传递一个标准布局对象到应用程序,并将其包装在应用程序端。
// plugin.h
struct PluginWriter{
void write(const char* str);
};
-
// plugin_impl.cpp
#include "plugin.h"
extern "C"{
PluginWriter* create_writer();
void delete_writer(PluginWriter* pw);
}
void PluginWriter::write(const char* str){
// . . .
}
-
// app
#include "plugin.h"
class WriterWrapper : public Writer{
private:
PluginWriter* the_plugin_writer; //object being wrapped
public:
WriterWrapper() : the_plugin_writer{ create_writer() }
{}
void write(std::string str) override{
the_plugin_writer->write( str.c_str() );
}
~WriterWrapper(){
delete_writer(the_plugin_writer);
}
};
但是,我担心链接器会在编译应用程序时抱怨,因为:#include plugin.h