Defining interface of abstract class in shared library

允我心安 提交于 2020-01-24 17:23:36

问题


Say I have a abstract base class defined like so:

interface.hpp

#ifndef INTERFACE_HPP
#define INTERFACE_HPP 1

class interface{
    public:
        virtual void func() = 0;
};

#endif // INTERFACE_HPP

Then I compile a translation unit test.cpp into a shared object 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;
}

If I open that shared object in an executable and try to call get_interface like this:

#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);
}

(just pretend I did error checking)

Is the behaviour well defined? Or am I stepping on my own toes by assuming this will always work?

Keep in mind I will only ever be using clang and gcc


回答1:


One gotcha is that you want protected: ~interface() to discourage clients from deleting interface.

A second, practical issue is that if you modify interface, remember to add the methods at the end of the class only, and do not add new virtual overrides (functions with the same name). (In practice, I have seen overrides be clustered together, even if they are not clustered in the header file).

If you want more than just a single interface (say, your interface inherits from 2 other interfaces), use virtual inheritance. Adding new virtual parents after the fact has in my experience proved problematic as well.

None of this is defined by the C++ standard, which is agnostic on the subject of binary interfaces and run time loading of code. However, the above is my experience using a similar technique (admittedly, with pointers instead of references, and using MSVC instead of gcc/clang).

You do have to keep track of what the ABI is on the compilers you use. If you pass std structures over such an interface, be aware that they sometimes change layout (std::string in gcc going from reference counted to not, for example, or std::list getting O(1) size), and they are not all that likely to be layout-compatible between compilers (well, standard libraries, which different compilers tend to use different ones by default).



来源:https://stackoverflow.com/questions/31407129/defining-interface-of-abstract-class-in-shared-library

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!