Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Распознавание структуры класса  (Прочитано 17484 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Setuper
Интересующийся

ru
Offline Offline

« : 01-02-2010 22:27 » 

Значит такая проблема...
В программе имеется абстрактный класс (SomeClassBase), при помощи которого дёргаются функции объекта (SomeClass) из dll библиотеки. Я подгружаю библиотеку динамически. Нахожу в библиотеке нужную мне функцию, которая строит этот самый объект внутри библиотеки, и возвращаю на эту функцию указатель (SomeClassBase * (*)(void)). После этого я вызываю эту самую функцию и записываю в некий указатель SomeClassBase* результат, возвращаемый этой функций. Так вот проблема в том, что если я захотел что-то изменить в абстрактном классе программы SomeClassBase, то если программа попытается загрузить старую версию библиотеки, то указатель SomeClassBase* будет указывать на что-то нехорошее и при попытках обратиться к каким-то членам класса SomeClassBase по средствам этого указателя программа упадёт. Как избежать падения и проверить соответствия между классом SomeClassBase в программе и классом SomeClassBase в dll библиотеке. Пробовал приведение типов dynamic_cast, но не помогло.

Помогите пожалуйста решить данную задачу.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #1 : 01-02-2010 22:42 » 

Самое простое решение. В базовом классе прописать функцию virtual int version() {return SOME_VERSION;} Соответственно в классах-потомках переопределять. Когда забираеш экземпляр класса, остается только проверять, соответствует ли версия твоим условиям.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #2 : 02-02-2010 04:46 » 

Finch, поддерживаю

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

ситуация 2:
старый интерфейс в dll
новый интерфейс в программе
Нет проблем, если:
- если поменял только имя, но не менял позицию в списке методов и не менял сигнатуру (да вот так)
- если программа умеет работать с разными версиями интерфейса.

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

совсем забыл, к неявному изменению интерфейса можно отнести изменение размеров структур которые гуляют через интерфейс, даже в виде указателей. правила те же, что и для самого интерфейса.
Записан

Странно всё это....
Setuper
Интересующийся

ru
Offline Offline

« Ответ #3 : 02-02-2010 22:22 » 

Попробовал предложенный вариант с версиями, но не прокатывает, так как при вызове этого метода version() идёт обращение к виртуальной функции объекта, который имеет отличную от этой структуру и программа сразу же падает в месте вызова этого метода.

Падения не будет только если сделать метод version() не виртуальным и только в базовом классе. Поэтому падение именно из-за попытки найти виртуальную функцию в производном классе в библиотеке.
« Последнее редактирование: 02-02-2010 22:30 от Setuper » Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #4 : 02-02-2010 22:29 » 

Ну тогда заводи в dll функцию version.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Setuper
Интересующийся

ru
Offline Offline

« Ответ #5 : 02-02-2010 22:41 » 

А что если сделать так: в базовом классе сделать поле bool no_load; и в конструкторе базового же класса написать no_load = false;
Конструктор базового класса вызывать в производном классе, а в программе проверять этот флаг. Если true, то значит объект не создан и структуры не совпадают, если false, то всё ок. Расчёт на то, что по умолчанию поля типа bool в структурах инициализируются как true, поэтому объект может и не быть создан, а поле будет проинициализировано значением true.
Или это очень корявый вариант??

Просто если обязательно создавать функцию version в dll библиотеке, то получается что левыми библиотеками можно уронить программу, а это - уязвимость.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #6 : 02-02-2010 22:52 » 

Setuper, Я не совсем понял смысла. Можно на пальцах более подробно объяснить. Что за такая крутая библиотека, что роняет всю программу. И если наследуешся от базового класса, то в дочерних классах внутреняя структура базового класса не совпадает.
Кстати проект пишется на одном языке и компилируется в одном компиляторе. Если нет, то это все Сизифов труд.
« Последнее редактирование: 02-02-2010 22:56 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Setuper
Интересующийся

ru
Offline Offline

« Ответ #7 : 02-02-2010 23:11 » 

Ну так я же в начале темы написал, что мол:
Цитата
если я захотел что-то изменить в абстрактном классе программы SomeClassBase, то если программа попытается загрузить старую версию библиотеки, то указатель SomeClassBase* будет указывать на что-то нехорошее и при попытках обратиться к каким-то членам класса SomeClassBase по средствам этого указателя программа упадёт. Как избежать падения и проверить соответствия между классом SomeClassBase в программе и классом SomeClassBase в dll библиотеке?
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #8 : 03-02-2010 04:47 » 

Попробовал предложенный вариант с версиями, но не прокатывает, так как при вызове этого метода version() идёт обращение к виртуальной функции объекта, который имеет отличную от этой структуру и программа сразу же падает в месте вызова этого метода.
такое ощущение, что ты не знаешь, как работают виртуальные функции

virtual version() = 0;
должна быть первой в списке методов!!!
« Последнее редактирование: 03-02-2010 04:50 от LogRus » Записан

Странно всё это....
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 03-02-2010 05:08 » 

Цитата
virtual version() = 0;
должна быть первой в списке методов!!!
Или вынести в абстрактный класс-родитель ?
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #10 : 03-02-2010 06:30 » new

Цитата
virtual version() = 0;
должна быть первой в списке методов!!!
Или вынести в абстрактный класс-родитель ?

ну об этом говорит virtual version() = 0; Улыбаюсь
хотя можно реализовать отдельный интерфейс для проверки версий, в этом случае version() может быть не первой, но тогда нельзя будет менять интерфейс проверки версий
Записан

Странно всё это....
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #11 : 03-02-2010 07:03 » 

1. Зачем пихать функцию getVersion в этот класс?
2. Зачем пихать функцию getVersion в какой-то класс, ее можно просто сделать отдельной  экспортируемой функцией библиотеки
3. От падения программы ты никуда не уйдешь если тебе намеренно подсовывают лажовую dll. Это не уязвимость, ну или можно предусмотреть модуль аутентификации и авторизации этой dll, но это уже параноя.
4. Если dll не фейковая, то прогу она не уронит поскольку класс/функцию (речь именно об интерфейсе, а не о реализации) менять не надо.
5. Если очень надо (хотя имхо это проблема проектирования) менять SomeClassBase в библиотеке, то меняйте не его, а сделайте лишнюю прослойку из еще одного виртуального класса , который будет наследником SomeClassBase, и от которого будет наследоваться SomeClass. В реализации библиотеки используйте эту прослойку, тогда все будет работать (повторю, я считаю это решение не очень удачным)

Посмотрите в сторону COM... Куча народа им пользуется... там железное правило интерфейс менять нельзя! Можно создать новый интерфейс и экспортировать его для новой версии клиента.
Записан

С уважением Lapulya
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #12 : 03-02-2010 08:17 » 

lapulya, тоже вариант, но лично мне интересна версия интерфейса, а не версия библиотеки, потому как интерфейс может поменяться 1 раз на 100 версий библиотеки.
Записан

Странно всё это....
Setuper
Интересующийся

ru
Offline Offline

« Ответ #13 : 03-02-2010 10:41 » 

lapulya, спасибо. Очень доходчиво всё расписал. Действительно, наверное я очень сильно заморачиваюсь по этому поводу, так как столкнулся с такой проблемой совместимости версий. С прослойкой там тоже не всё гладко будет, ну да ладно. Пока что на 100% работает предложенный мною вариант с "булом".

Цитата
такое ощущение, что ты не знаешь, как работают виртуальные функции

virtual version() = 0;
должна быть первой в списке методов!!!
Во-первых, было предложено написать в базовом классе не чисто виртуальный метод. Во-вторых, чисто виртуальный метод и подавно будет искать данную функцию в производном классе, и порядок в списке методов тут влиять никак не будет (проверял). В-третьих, virtual int version() = 0;  Ага В-четвёртых, базовый класс, с которым идёт работа в программе, итак является абстрактным.
« Последнее редактирование: 03-02-2010 10:52 от Setuper » Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #14 : 03-02-2010 11:00 » 

Setuper, вы просто не умеете их готовить.
Записан

Странно всё это....
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #15 : 03-02-2010 21:14 » 

Ну если нужна версия самого интерфейса, то приходим к тому, как это работает в СОМ и никаких проблем. Т.е., есть интерфейс SomeClassBase и его реализация SomeClass. Надо "изменить" интерфейс, делаем так: оставляем SomeClassBase как есть? делаем новый интерфейс NEWSomeClassBase. Наследуем SomeClass от обоих интерфейсов, закрываем оба интерфейса реализацией из SomeClass. Экспортируем оба интерфейса. Старые клиенты используют SomeClassBase, а новые NEWSomeClassBase. И заметьте никаких лишних функций getVersion.
Записан

С уважением Lapulya
Setuper
Интересующийся

ru
Offline Offline

« Ответ #16 : 04-02-2010 12:31 » 

Setuper, не "чисто виртуальный метод " , а "чистый виртуальный"  Улыбаюсь
Почитайте Страуструпа. У него чёрным по белому написано: "чисто виртуальная функция" (изд.3, 2007г., стр361).  Улыбаюсь

lapulya, спасибо за объяснение, однако нагромождать лишними классами не хочется, хотя по реализации вроде все прозрачно.
« Последнее редактирование: 04-02-2010 12:41 от Setuper » Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #17 : 05-02-2010 06:04 » 

инкапсуляция великая вещь, за ней нагромождений не видно...

ЗЫ (это к нагромождениям)
(имхо враппер, врапперу не помеха Улыбаюсь лишь бы без копирования буферов)
Записан

С уважением Lapulya
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines