【问题标题】:Defining interface of abstract class in shared library在共享库中定义抽象类的接口
【发布时间】:2015-10-03 02:52:46
【问题描述】:

假设我有一个这样定义的抽象基类:

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

【问题讨论】:

标签: c++ c++14 dlopen dlsym


【解决方案1】:

一个问题是您希望protected: ~interface() 阻止客户删除interface

第二个实际问题是,如果你修改interface,记得只在类的end添加方法,不要添加新的虚拟覆盖(同名的函数) )。 (在实践中,我已经看到覆盖聚集在一起,即使它们没有聚集在头文件中)。

如果您想要的不仅仅是一个接口(例如,您的接口继承自其他 2 个接口),请使用virtual 继承。事后添加新的virtual 父母也有问题。

这些都不是由 C++ 标准定义的,它与二进制接口和代码运行时加载的主题无关。但是,以上是我使用类似技术的经验(诚然,使用指针而不是引用,并使用 MSVC 代替 gcc/clang)。

您必须跟踪您使用的编译器上的 ABI 是什么。如果您通过这样的接口传递std 结构,请注意它们有时会更改布局(例如,gcc 中的std::string 从引用计数变为不计数,或者std::list 得到O(1) size),并且它们并不是所有编译器之间的布局兼容(嗯,标准库,不同的编译器默认使用不同的编译器)。

【讨论】:

    猜你喜欢
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 2011-11-09
    • 2021-04-02
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多