Setuper
Интересующийся
Offline
|
|
« : 01-02-2010 22:27 » |
|
Значит такая проблема... В программе имеется абстрактный класс (SomeClassBase), при помощи которого дёргаются функции объекта (SomeClass) из dll библиотеки. Я подгружаю библиотеку динамически. Нахожу в библиотеке нужную мне функцию, которая строит этот самый объект внутри библиотеки, и возвращаю на эту функцию указатель (SomeClassBase * (*)(void)). После этого я вызываю эту самую функцию и записываю в некий указатель SomeClassBase* результат, возвращаемый этой функций. Так вот проблема в том, что если я захотел что-то изменить в абстрактном классе программы SomeClassBase, то если программа попытается загрузить старую версию библиотеки, то указатель SomeClassBase* будет указывать на что-то нехорошее и при попытках обратиться к каким-то членам класса SomeClassBase по средствам этого указателя программа упадёт. Как избежать падения и проверить соответствия между классом SomeClassBase в программе и классом SomeClassBase в dll библиотеке. Пробовал приведение типов dynamic_cast, но не помогло.
Помогите пожалуйста решить данную задачу.
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #1 : 01-02-2010 22:42 » |
|
Самое простое решение. В базовом классе прописать функцию virtual int version() {return SOME_VERSION;} Соответственно в классах-потомках переопределять. Когда забираеш экземпляр класса, остается только проверять, соответствует ли версия твоим условиям.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Антон (LogRus)
|
|
« Ответ #2 : 02-02-2010 04:46 » |
|
Finch, поддерживаю в дополнение к сказанному ситуация 1: старый интерфейс в программе новый интерфейс в dll Нет проблем, если: - если не менял сигнатуру старых методов - если не менял поведение. (Не исправление ошибок, а на пример, решил, что поведение не соответствует имени) - если поменял только имя, но не менял позицию в списке методов, не менял сигнатуру и не менял поведение (да вот так) - если новые методы добавлялись в конец списка - если старые методы не переставлялись в списке ситуация 2: старый интерфейс в dll новый интерфейс в программе Нет проблем, если: - если поменял только имя, но не менял позицию в списке методов и не менял сигнатуру (да вот так) - если программа умеет работать с разными версиями интерфейса. т.е. при желании программа может не парится насчёт интерфейса (если ты позаботился об обратной совместимости, довольно часто именно так и бывает, разработчики заботятся друг о друге ), если версия интерфейса в dll выше или равна версии в программе совсем забыл, к неявному изменению интерфейса можно отнести изменение размеров структур которые гуляют через интерфейс, даже в виде указателей. правила те же, что и для самого интерфейса.
|
|
|
Записан
|
Странно всё это....
|
|
|
Setuper
Интересующийся
Offline
|
|
« Ответ #3 : 02-02-2010 22:22 » |
|
Попробовал предложенный вариант с версиями, но не прокатывает, так как при вызове этого метода version() идёт обращение к виртуальной функции объекта, который имеет отличную от этой структуру и программа сразу же падает в месте вызова этого метода.
Падения не будет только если сделать метод version() не виртуальным и только в базовом классе. Поэтому падение именно из-за попытки найти виртуальную функцию в производном классе в библиотеке.
|
|
« Последнее редактирование: 02-02-2010 22:30 от Setuper »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #4 : 02-02-2010 22:29 » |
|
Ну тогда заводи в dll функцию version.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Setuper
Интересующийся
Offline
|
|
« Ответ #5 : 02-02-2010 22:41 » |
|
А что если сделать так: в базовом классе сделать поле bool no_load; и в конструкторе базового же класса написать no_load = false; Конструктор базового класса вызывать в производном классе, а в программе проверять этот флаг. Если true, то значит объект не создан и структуры не совпадают, если false, то всё ок. Расчёт на то, что по умолчанию поля типа bool в структурах инициализируются как true, поэтому объект может и не быть создан, а поле будет проинициализировано значением true. Или это очень корявый вариант??
Просто если обязательно создавать функцию version в dll библиотеке, то получается что левыми библиотеками можно уронить программу, а это - уязвимость.
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #6 : 02-02-2010 22:52 » |
|
Setuper, Я не совсем понял смысла. Можно на пальцах более подробно объяснить. Что за такая крутая библиотека, что роняет всю программу. И если наследуешся от базового класса, то в дочерних классах внутреняя структура базового класса не совпадает. Кстати проект пишется на одном языке и компилируется в одном компиляторе. Если нет, то это все Сизифов труд.
|
|
« Последнее редактирование: 02-02-2010 22:56 от Finch »
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Setuper
Интересующийся
Offline
|
|
« Ответ #7 : 02-02-2010 23:11 » |
|
Ну так я же в начале темы написал, что мол: если я захотел что-то изменить в абстрактном классе программы SomeClassBase, то если программа попытается загрузить старую версию библиотеки, то указатель SomeClassBase* будет указывать на что-то нехорошее и при попытках обратиться к каким-то членам класса SomeClassBase по средствам этого указателя программа упадёт. Как избежать падения и проверить соответствия между классом SomeClassBase в программе и классом SomeClassBase в dll библиотеке?
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #8 : 03-02-2010 04:47 » |
|
Попробовал предложенный вариант с версиями, но не прокатывает, так как при вызове этого метода version() идёт обращение к виртуальной функции объекта, который имеет отличную от этой структуру и программа сразу же падает в месте вызова этого метода.
такое ощущение, что ты не знаешь, как работают виртуальные функции virtual version() = 0; должна быть первой в списке методов!!!
|
|
« Последнее редактирование: 03-02-2010 04:50 от LogRus »
|
Записан
|
Странно всё это....
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #9 : 03-02-2010 05:08 » |
|
virtual version() = 0; должна быть первой в списке методов!!!
Или вынести в абстрактный класс-родитель ?
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #10 : 03-02-2010 06:30 » |
|
virtual version() = 0; должна быть первой в списке методов!!!
Или вынести в абстрактный класс-родитель ? ну об этом говорит virtual version() = 0; хотя можно реализовать отдельный интерфейс для проверки версий, в этом случае version() может быть не первой, но тогда нельзя будет менять интерфейс проверки версий
|
|
|
Записан
|
Странно всё это....
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #11 : 03-02-2010 07:03 » |
|
1. Зачем пихать функцию getVersion в этот класс? 2. Зачем пихать функцию getVersion в какой-то класс, ее можно просто сделать отдельной экспортируемой функцией библиотеки 3. От падения программы ты никуда не уйдешь если тебе намеренно подсовывают лажовую dll. Это не уязвимость, ну или можно предусмотреть модуль аутентификации и авторизации этой dll, но это уже параноя. 4. Если dll не фейковая, то прогу она не уронит поскольку класс/функцию (речь именно об интерфейсе, а не о реализации) менять не надо. 5. Если очень надо (хотя имхо это проблема проектирования) менять SomeClassBase в библиотеке, то меняйте не его, а сделайте лишнюю прослойку из еще одного виртуального класса , который будет наследником SomeClassBase, и от которого будет наследоваться SomeClass. В реализации библиотеки используйте эту прослойку, тогда все будет работать (повторю, я считаю это решение не очень удачным)
Посмотрите в сторону COM... Куча народа им пользуется... там железное правило интерфейс менять нельзя! Можно создать новый интерфейс и экспортировать его для новой версии клиента.
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Антон (LogRus)
|
|
« Ответ #12 : 03-02-2010 08:17 » |
|
lapulya, тоже вариант, но лично мне интересна версия интерфейса, а не версия библиотеки, потому как интерфейс может поменяться 1 раз на 100 версий библиотеки.
|
|
|
Записан
|
Странно всё это....
|
|
|
Setuper
Интересующийся
Offline
|
|
« Ответ #13 : 03-02-2010 10:41 » |
|
lapulya, спасибо. Очень доходчиво всё расписал. Действительно, наверное я очень сильно заморачиваюсь по этому поводу, так как столкнулся с такой проблемой совместимости версий. С прослойкой там тоже не всё гладко будет, ну да ладно. Пока что на 100% работает предложенный мною вариант с "булом". такое ощущение, что ты не знаешь, как работают виртуальные функции
virtual version() = 0; должна быть первой в списке методов!!! Во-первых, было предложено написать в базовом классе не чисто виртуальный метод. Во-вторых, чисто виртуальный метод и подавно будет искать данную функцию в производном классе, и порядок в списке методов тут влиять никак не будет (проверял). В-третьих, virtual int version() = 0; В-четвёртых, базовый класс, с которым идёт работа в программе, итак является абстрактным.
|
|
« Последнее редактирование: 03-02-2010 10:52 от Setuper »
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #14 : 03-02-2010 11:00 » |
|
Setuper, вы просто не умеете их готовить.
|
|
|
Записан
|
Странно всё это....
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #15 : 03-02-2010 21:14 » |
|
Ну если нужна версия самого интерфейса, то приходим к тому, как это работает в СОМ и никаких проблем. Т.е., есть интерфейс SomeClassBase и его реализация SomeClass. Надо "изменить" интерфейс, делаем так: оставляем SomeClassBase как есть? делаем новый интерфейс NEWSomeClassBase. Наследуем SomeClass от обоих интерфейсов, закрываем оба интерфейса реализацией из SomeClass. Экспортируем оба интерфейса. Старые клиенты используют SomeClassBase, а новые NEWSomeClassBase. И заметьте никаких лишних функций getVersion.
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Setuper
Интересующийся
Offline
|
|
« Ответ #16 : 04-02-2010 12:31 » |
|
Setuper, не "чисто виртуальный метод " , а "чистый виртуальный" Почитайте Страуструпа. У него чёрным по белому написано: " чисто виртуальная функция" (изд.3, 2007г., стр361). lapulya, спасибо за объяснение, однако нагромождать лишними классами не хочется, хотя по реализации вроде все прозрачно.
|
|
« Последнее редактирование: 04-02-2010 12:41 от Setuper »
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #17 : 05-02-2010 06:04 » |
|
инкапсуляция великая вещь, за ней нагромождений не видно... ЗЫ (это к нагромождениям) (имхо враппер, врапперу не помеха лишь бы без копирования буферов)
|
|
|
Записан
|
С уважением Lapulya
|
|
|
|