2015-07-14 5 views
1

Скажем, у меня есть абстрактный базовый класс, определенный как так:Определение интерфейса абстрактного класса в общей библиотеке

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

(только делают вид, что я сделал проверку ошибок)

корректно определено поведение? Или я нахожусь на своих пальцах, полагая, что это всегда будет работать?

Имейте в виду, я только когда-либо использовать лязг и GCC

+0

Если вы используете один и тот же компилятор, то я не вижу причин, по которым это может пойти не так. Я просто портировал ваш образец на msvc (2015rc), и он там тоже работает. –

+0

Вы должны быть в порядке, если поддерживаете двоичную совместимость. См. Эти ... http://stackoverflow.com/questions/1774911/how-to-design-ac-api-for-binary-compatible-extensibility https://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++ http://stackoverflow.com/questions/3217513/are-llvm-gcc-and-clang-binary-compatible-with-gcc-particularly-mingw-gcc-on-w – QuestionC

ответ

0

Один Гоча является то, что вы хотите protected: ~interface() препятствовать клиентов от удаления interface.

Второй, практический вопрос заключается в том, что если вы измените interface, не забудьте добавить методы в конце лишь в классе, и не добавлять новые виртуальные переопределяет (функции с тем же именем). (На практике я видел, что переопределения группируются вместе, даже если они не кластеризованы в заголовочном файле).

Если вы хотите больше, чем просто один интерфейс (скажем, ваш интерфейс наследуется от 2 других интерфейсов), используйте virtual наследование. Добавление новых virtual родителей после того, как факт в моем опыте оказался проблематичным.

Ничего из этого не определено стандартом C++, который является агностиком для двоичных интерфейсов и времени загрузки кода. Тем не менее, это мой опыт использования подобной техники (по общему признанию, с указателями вместо ссылок и использованием MSVC вместо gcc/clang).

Вам необходимо отслеживать, что ABI находится на используемых вами компиляторах. Если вы передаете std структуры над таким интерфейсом, имейте в виду, что они иногда меняют макет (std::string в gcc, идущем от ссылки, подсчитанной, например, или std::list, получая O (1) size), и они не все, что может быть совместимость с макетами между компиляторами (ну, стандартные библиотеки, которые по умолчанию используют разные компиляторы).

Смежные вопросы