Наследование от динамически импортируемого класса, Возможно ли такое? Интересует реализация под MinGW |
Здравствуйте, гость ( Вход | Регистрация )
Наследование от динамически импортируемого класса, Возможно ли такое? Интересует реализация под MinGW |
Iron Bug |
14.2.2011, 9:57
Сообщение
#1
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
Можно ли такое реализовать?
Допустим, есть примерно такой код (собираю под под MinGW): В основном модуле:
В загружаемой динамической библиотеке:
Идея в том, чтобы в основном модуле был базовый класс Base со всеми причиндалами (туда же компилится и его код). А в подгружаемых через LoadLibrary (и заранее неизвестных) библиотеках - дополнительные классы-наследники Derived , которые бы вызывали конструкторы/деструкторы базового класса, а сами были бы экспортируемыми, чтобы основной модуль мог их загружать и использовать. Копаю-копаю, и вот ну никак! При такой реализации вроде бы должно работать, но линкер при сборке dll (__DLL при этом определён) вопит, что декорированное имя импорта конструктора базового класса не определено. Вообще, теоретически, все базовые классы экспортируемого класса тоже должны быть экспортируемыми. Ну, я пыталась добавить в Base ещё и dllexport, но не проканало. То ли неправильно добавляла, то ли это вообще компилятор не жрёт. Он не ругается на такой двойной import-export, но и ошибка не исчезает. Сообщение отредактировал Iron Bug - 14.2.2011, 9:57 |
|
|
Iron Bug |
15.2.2011, 20:37
Сообщение
#2
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
в общем, ковыряла-ковыряла и решила-таки эту задачу. правда, чуть окольным путём:
теперь у меня две библиотеки и основной модуль. в библиотеках - базовый класс и класс-наследник. библиотека наследника линкуется динамической связью с библиотекой базового класса. а основной модуль грузит класс-наследник из библиотеки через dlopen (ну или LoadLibrary под вендой). если потомок не реализует метод, то вызывается метод предка, из базовой библиотеки. всё работает и под вендой, и под линём. правда, пришлось кое-где idfef'ы налепить и с флагами линковки всего этого безобразия повозиться, чтобы работало как надо. и пока создание представителя класса сделано через специальные методы, а не подменой указателей в виртуальных таблицах, хотя можно и напрямую класс грузить из библиотеки, если маленько ассемблера добавить. Сообщение отредактировал Iron Bug - 15.2.2011, 20:37 |
|
|
ViGOur |
19.2.2011, 23:23
Сообщение
#3
|
Мастер Группа: Модератор Сообщений: 3296 Регистрация: 9.10.2007 Из: Москва Пользователь №: 4 Спасибо сказали: 231 раз(а) Репутация: 40 |
Сам не писал подобного, но читал статью как подобное реализовать на рсдн, вот только найти не могу, так как давно уже читал.
Ты лучше описание кодом как реализовала выложи... |
|
|
Iron Bug |
21.2.2011, 14:45
Сообщение
#4
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
у меня тут кода слишком дофига. проект жирный, много-много библиотек, полная кроссплатформа, буст и надо специально сидеть и выкусывать куски настроек, относящиеся к данной подзадаче.
но если кому очень приспичит, могу пошариться и выписать. только не срочно, а то у меня тут большой проект с парсерами и работой с кучей железа. я по уши в работе, днём и ночью. сейчас вот добила интерфейс для ещё одной шины и вылезла в сеть - мозг разгрузить маленько |
|
|
Iron Bug |
12.3.2011, 17:28
Сообщение
#5
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
Я тут обнаружила потребность народа в некотором примере насчёт использования динамических библиотек.
Вот, вытащила из своего проекта куски, относящиеся к загрузке и вызовам. Смысл примера такой: есть приложение, которое грузит (динамически) библиотеки с некоторым интерфейсом (IInterface). Все загружаемые библиотеки наследуют некоторое дефолтное поведение от базового класса (Base). Если библиотека не реализует какой-то метод интерфейса, то будет вызван базовый метод. Это чтобы не переписывать в каждой библиотеке одни и те же действия. Пример загружаемой библиотеки - Derived. Я привела флаги компиляции и сборки для разных систем (я собираю под линюксом с gcc и icc и под вендой с mingw). Вроде ничего не забыла, но возможно, что некоторые флаги не нужны для данного примера (я их поместила в квадратные скобки [...]). Просто у меня проект большой и там много чего ещё кроме этого, поэтому там могли оказаться не относящиеся к данной подзадаче параметры. Да, стандартные флаги для библиотек типа -ldl я сюда не выписывала. Выписаны только специфические параметры. Какие плюсы? Собственно, независимость библиотек от основного кода. Для добавления функционала достаточно перекомпилять загружаемые модули. Базовый функционал класса Base можно менять, не пересобирая библиотеки, которые его используют. Надеюсь, что в принципе понятно. Общий файл интерфейса 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 Раскрывающийся текст
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 Раскрывающийся текст
Пример реализации основной динамически загружаемой библиотеки Derived.cpp Раскрывающийся текст
Инструкции по сборке вызывающей программы: gcc,icc: CXXFLAGS: -fPIC LDFLAGS: mingw: CXXFLAGS: LDFLAGS: -enable-auto-import [-enable-runtime-pseudo-reloc] [-Wl,--allow-multiple-definition] -Wl,--kill-at Пример загрузки/выгрузки библиотеки Derived и использования класса (вызов метода init): Раскрывающийся текст
Примечание: при вызове _pInterface->init() будет вызван метод init класса Derived. Сообщение отредактировал Iron Bug - 12.3.2011, 18:08 |
|
|
PAFOS |
6.6.2011, 16:12
Сообщение
#6
|
Активный участник Группа: Участник Сообщений: 258 Регистрация: 27.12.2010 Из: Дмитров Пользователь №: 2309 Спасибо сказали: 29 раз(а) Репутация: 8 |
напоминает технологию COM мелкософта.
|
|
|
Iron Bug |
6.6.2011, 22:58
Сообщение
#7
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
|
|
|
PAFOS |
7.6.2011, 8:10
Сообщение
#8
|
Активный участник Группа: Участник Сообщений: 258 Регистрация: 27.12.2010 Из: Дмитров Пользователь №: 2309 Спасибо сказали: 29 раз(а) Репутация: 8 |
Имхо счетчик ссылок тут лишь способ правильного управления временем жизни объекта. *
Однако СОМ это ведь не только счетчик ссылок. Клиент (Приложение) знает об интерфейсе IUnknown и знает об интерфейсе, который несет полезную нагрузку. Через IUnknown клиент может узнать поддерживает ли сервер (СОМ объект) нужный ему интерфейс. Так же через IUnknown ведется подсчет ссылок. Но это только вершина айсберга... t;line-height:100%">*Iron Bug, рано или поздно (если будешь развивать эту тему) ты придешь к вопросу о моменте удаления объекта. В данной версии момент удаления объекта определяет программист (правильно ли я понял?), использующий объект, а не программист, разрабатывающий сам объект. Это конечно по нашему, по С++вски, но накладывает на ленивого программиста дополнительные обязанности. |
|
|
Iron Bug |
7.6.2011, 20:27
Сообщение
#9
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
ну, если прога загружает библиотеку и создаёт представитель класса, то она же его и убивает. тут проблем не возникает. единственное, за чем следит сам юзер - это очистка ео локальных переменных и правильное завершение работы после вызова деструктора.
на самом деле, для меня это не проблема, потому что я - единственный разработчик "плагинов" для своей софтины проблема в том, что надо уметь динамически, где-то в поле, расширять функционал, без пересборки основной софтины. и эту проблему я решила через такие расширения, которые просто прописываются в конфиге и подгружаются динамически. |
|
|
PAFOS |
9.6.2011, 8:05
Сообщение
#10
|
Активный участник Группа: Участник Сообщений: 258 Регистрация: 27.12.2010 Из: Дмитров Пользователь №: 2309 Спасибо сказали: 29 раз(а) Репутация: 8 |
с этими плагинами надо очень быть предусмотрительным)
Нередки случаи когда с нужно в очередной раз расширить приложение, а интерфейсы, заложенные в него, уже не способны решить требуемые задачи. Мне тут однажды попалась на глаза программа SharpDevelop (опен сорс IDE для разработки на .Net). У нее мне понравилась система плагинов - там есть возможность расширять одни плагины другими. Очень интересная идея имхо) |
|
|
Текстовая версия | Сейчас: 29.3.2024, 11:49 |