crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

> Наследование от динамически импортируемого класса, Возможно ли такое? Интересует реализация под MinGW
Iron Bug
  опции профиля:
сообщение 14.2.2011, 9:57
Сообщение #1


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


Можно ли такое реализовать?
Допустим, есть примерно такой код (собираю под под MinGW):

В основном модуле:
#ifdef __DLL
    #define __DLL_BASE __attribute__((dllimport))
#else
    #define __DLL_BASE __attribute__((dllexport))
#endif

class __DLL_BASE Base
{
  public:
     Base() {};
     ~Base() {};
...
};


В загружаемой динамической библиотеке:
#ifdef __DLL
    #define __DLL_DERV __attribute__((dllexport))
#else
    #define __DLL_DERV __attribute__((dllimport))
#endif

class __DLL_DERV Derived : public Base
{
   public:
      Derived() {};
      ~Derived() {};
...
};


Идея в том, чтобы в основном модуле был базовый класс Base со всеми причиндалами (туда же компилится и его код). А в подгружаемых через LoadLibrary (и заранее неизвестных) библиотеках - дополнительные классы-наследники Derived , которые бы вызывали конструкторы/деструкторы базового класса, а сами были бы экспортируемыми, чтобы основной модуль мог их загружать и использовать.
Копаю-копаю, и вот ну никак! При такой реализации вроде бы должно работать, но линкер при сборке dll (__DLL при этом определён) вопит, что декорированное имя импорта конструктора базового класса не определено. Вообще, теоретически, все базовые классы экспортируемого класса тоже должны быть экспортируемыми. Ну, я пыталась добавить в Base ещё и dllexport, но не проканало. То ли неправильно добавляла, то ли это вообще компилятор не жрёт. Он не ругается на такой двойной import-export, но и ошибка не исчезает.

Сообщение отредактировал Iron Bug - 14.2.2011, 9:57
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
Iron Bug
  опции профиля:
сообщение 12.3.2011, 17:28
Сообщение #2


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


Я тут обнаружила потребность народа в некотором примере насчёт использования динамических библиотек.
Вот, вытащила из своего проекта куски, относящиеся к загрузке и вызовам.
Смысл примера такой: есть приложение, которое грузит (динамически) библиотеки с некоторым интерфейсом (IInterface).
Все загружаемые библиотеки наследуют некоторое дефолтное поведение от базового класса (Base). Если библиотека не реализует какой-то метод интерфейса, то будет вызван базовый метод. Это чтобы не переписывать в каждой библиотеке одни и те же действия.
Пример загружаемой библиотеки - Derived.
Я привела флаги компиляции и сборки для разных систем (я собираю под линюксом с gcc и icc и под вендой с mingw).
Вроде ничего не забыла, но возможно, что некоторые флаги не нужны для данного примера (я их поместила в квадратные скобки [...]). Просто у меня проект большой и там много чего ещё кроме этого, поэтому там могли оказаться не относящиеся к данной подзадаче параметры. Да, стандартные флаги для библиотек типа -ldl я сюда не выписывала. Выписаны только специфические параметры.
Какие плюсы? Собственно, независимость библиотек от основного кода. Для добавления функционала достаточно перекомпилять загружаемые модули. Базовый функционал класса Base можно менять, не пересобирая библиотеки, которые его используют.

Надеюсь, что в принципе понятно.

Общий файл интерфейса Interface.h
Раскрывающийся текст
#ifndef __INTERFACE_H__
#define __INTERFACE_H__

// interface
class IInterface
{
public:
    IInterface() {};
    virtual ~IInterface() {};
    virtual void init() = 0;
};

// types for class instance creators/destroyers 
typedef IInterface *(*funcInterfaceCreate_type)();
typedef void (*funcInterfaceDelete_type)(IInterface *);

#endif // __INTERFACE_H__


Инструкции по сборке базовой библиотеки Base:
gcc,icc:
CXXFLAGS: -fPIC
LDFLAGS: -nodefaultlibs -shared

mingw:
для венды установить дефайн__DLL (для экспорта)
CXXFLAGS:
LDFLAGS: -enable-auto-import [-enable-runtime-pseudo-reloc] -Wl,--kill-at

Заголовок базового класса Base.h
Раскрывающийся текст
#ifndef __BASE_H__
#define __BASE_H__

#include "Interface.h"

#ifndef __linux__
#ifdef __DLL
#define __BASE_DLL __declspec(dllexport)
#else
#define __BASE_DLL __declspec(dllimport)
#endif
#else
#define __BASE_DLL
#endif

class __BASE_DLL Base : public IInterface
{
protected:
    int _param;
public:
    Base();
    virtual ~Base();
    virtual void init();
};

#endif


Base.cpp не привожу, он тут не важен. Там можно что-то выполнять, какие-то базовые действия.

Инструкции по сборке библиотеки Derived:
gcc,icc:
CXXFLAGS: -fPIC [-enable-runtime-pseudo-reloc]
LDFLAGS: -nodefaultlibs -shared -lBase

mingw:
для венды установить дефайн __DLL (для экспорта)
CXXFLAGS:
LDFLAGS: -enable-auto-import [-Wl,--allow-multiple-definition]

Заголовок файла основной динамически загружаемой библиотеки Derived.h
Раскрывающийся текст
#ifndef __DERIVED_H__
#define __DERIVED_H__

#include "Base.h" 

#ifndef __linux__
#ifdef __DLL
    #define __DERIVED_DLL __declspec(dllexport)
#else
    #define __DERIVED_DLL __declspec(dllimport)
#endif
#else
#define __DERIVED_DLL
#endif

class __DERIVED_DLL Derived : public Base
{
    public:
        Derived();
        virtual ~Derived();
        virtual void init();
};
#endif


Пример реализации основной динамически загружаемой библиотеки Derived.cpp
Раскрывающийся текст
#include "Derived.h"

Derived::Derived() : Base()
{}

Derived::~Derived()
{}

void Derived::init()
{
    Base::init();
}

#ifdef __cplusplus
extern "C" {
#endif

IInterface
#ifndef __linux__
__stdcall __DERIVED_DLL
#endif
*CreateObject()
{
    return (IInterface*)new Derived();
}

void
#ifndef __linux__
__stdcall __DERIVED_DLL
#endif
DeleteObject(IInterface *pDerived)
{
    if(pDerived==0) throw;
    delete(pDerived);
}

#ifdef __cplusplus
}
#endif


Инструкции по сборке вызывающей программы:
gcc,icc:
CXXFLAGS: -fPIC
LDFLAGS:

mingw:
CXXFLAGS:
LDFLAGS: -enable-auto-import [-enable-runtime-pseudo-reloc] [-Wl,--allow-multiple-definition] -Wl,--kill-at

Пример загрузки/выгрузки библиотеки Derived и использования класса (вызов метода init):
Раскрывающийся текст
#include "IInteface.h"

#ifdef __linux__
void *_pDll; // linux handle for dynamic library
#else
HMODULE _hDll; // windows handle for dynamic library
#endif

funcInterfaceCreate_type _pFuncCreateObject; //pointer to CreateObject function in dll
funcInterfaceDelete_type _pFuncDeleteObject; //pointer to DeleteObject function in dll

IInterface *_pInterface;

void load()
{
#ifdef __linux__
    _pDll = dlopen("libDerived.so",RTLD_NOW);
    if(_pDll != 0)
    {
        union
        {
            funcInterfaceCreate_type func;
            void *ptr;
        } uniCreate;
        uniCreate.ptr = dlsym(_pDll,"CreateObject");
        _pFuncCreateObject = uniCreate.func;
        union
        {
            funcInterfaceDelete_type func;
            void *ptr;
        } uniDelete;
        uniDelete.ptr = dlsym(_pDll,"DeleteObject");
        _pFuncDeleteObject = uniDelete.func;
    }
#else
    _hDll = LoadLibrary("Derived.dll");
    if(_hDll != NULL)
    {
        _pFuncCreateObject = (funcInterfaceCreate_type)GetProcAddress(_hDll,"CreateObject");
        _pFuncDeleteObject = (funcInterfaceDelete_type)GetProcAddress(_hDll,"DeleteObject");
    }
#endif
    _pInterface = (*_pFuncCreateObject)();
}

void unload()
{
    (*_pFuncDeleteObject)(_pInterface);

#ifdef __linux__
    dlclose(_pDll);
#else
    FreeLibrary(_hDll);
#endif
}

void use()
{
    _pInterface->init();
}


Примечание: при вызове _pInterface->init() будет вызван метод init класса Derived.

Сообщение отредактировал Iron Bug - 12.3.2011, 18:08
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0


RSS Рейтинг@Mail.ru Текстовая версия Сейчас: 24.6.2025, 7:11