HLFX.Ru Forum
профиль •  правила •  регистрация •  календарь •  народ •  FAQ •  поиск •  новое •  сутки •  главная •  выход  
HLFX.Ru Forum HLFX.Ru Forum > Наш форум > Технические вопросы > C++ и виртуальное наследование
Грабли №100500
  Предыдущая тема   Следующая тема
Автор
Тема Новая тема    Ответить
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34512
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


C++ и виртуальное наследование

Вопрос к знатокам теории или тем, кто сталкивался.
Имеем стандартную ситуацию "ромбовидное наследование" с одним хитрым нюансом: клиент библиотеки видит только интерфейсы и не использует RTTI.

Код следующий:

1. Библиотека:

C++ Source Code:
1
// Видимо клиенту
2
class AInterface
3
{
4
public:
5
  virtual void foo() = 0;
6
};
7
class BInterface : public virtual AInterface
8
{
9
public:
10
  virtual void bar() = 0;
11
};
12
extern "C" __declspec(dllexport) void *get_B();
13
 
14
// невидимо клиенту
15
class AImplementation : public virtual AInterface
16
{
17
public:
18
  virtual void foo() {};
19
};
20
class BImplementation : public [b][size=4]virtual[/size][/b] BInterface, public AImplementation
21
{
22
public:
23
  virtual void bar() {};
24
}
25
__declspec(dllexport) void *get_B()
26
{
27
  BInterface *lib_b = new BImplementation;
28
  return lib_b;
29
}


2. Клиент:
C++ Source Code:
1
// Те же интерфейсы из библиотеки
2
class AInterface
3
{
4
public:
5
  virtual void foo() = 0;
6
};
7
class BInterface : public virtual AInterface
8
{
9
public:
10
  virtual void bar() = 0;
11
};
12
 
13
extern "C" __declspec(dllimport) void *get_B();
14
 
15
// Клиентский код
16
void somefunc()
17
{
18
  BInterface *b = static_cast<BInterface*>( get_B() );
19
  b->bar(); // EPIC FAIL!
20
}


При вызове на клиенте b->bar() всё рушится. Если посмотреть в отладчике - выясняется, что таблица виртуальных функций b содержит какую-то иррунду. При этом в библиотеке lib_b содержит эту таблицу правильную.
А дальше всё намного интереснее. Убираем виртуальное наследование от BInterface в библиотеке (я выделил это место), и баг пропадает: даже несмотря на статик_каст, клиентский b содержит правильную таблицу виртуальных функций.

Кто может объяснить это поведение? Насколько оно надёжно? Будет ли это работать в GCC, или это некий благоприятный баг MSVC2010, надеяться на который не стоит?

Добавлено 15-12-2015 в 23:57:

Второй вариант, который работает: слово virtual не трогаем, а меняем сигнатуру у get_B:
C++ Source Code:
1
// Либа
2
__declspec(dllexport) BInterface *get_B()
3
{
4
  BInterface *lib_b = new BImplementation;
5
  return lib_b;
6
}
7
// Клиент
8
extern "C" __declspec(dllimport) BInterface *get_B();

Так тоже всё работает (статик_каст в этом случае, разумеется, делать не нужно).
Насколько надёжен этот вариант в сравнении с первым?

Сообщить модератору | | IP: Записан
Сообщение: 152336

Старое сообщение 15-12-2015 17:57
-
ComradeAndrew
Житель форума

Дата регистрации: Aug 2014
Проживает: Дубай
Сообщений: 510
Возраст: 27

Рейтинг



А у меня первый вариант не крашит.
toolset v140
Если я нигде не ошибся, копируя код %)

Сообщить модератору | | IP: Записан
Сообщение: 152358

Старое сообщение 16-12-2015 04:36
- За что?
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34512
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


Гм, возможно, ломается в более сложных примерах. Там, где и у AImplementation, и у BImplementation есть данные и невиртуальные функции, а также самих виртуальных функций в интерфейсах много. Как у меня и есть в реальном проекте.

Сообщить модератору | | IP: Записан
Сообщение: 152360

Старое сообщение 16-12-2015 06:01
-
Тема: (Опционально)
Ваш ответ:



Переводчик транслита


[проверить длину сообщения]
Опции: Автоматическое формирование ссылок: автоматически добавлять [url] и [/url] вокруг интернет адресов.
Уведомление по E-Mail: отправить вам уведомление, если кто-то ответил в тему (только для зарегистрированных пользователей).
Отключить смайлики в сообщении: не преобразовывать текстовые смайлики в картинки.
Показать подпись: добавить вашу подпись в конец сообщения (только зарегистрированные пользователи могут иметь подписи).

Временная зона GMT. Текущее время 17:17. Новая тема    Ответить
  Предыдущая тема   Следующая тема
HLFX.Ru Forum HLFX.Ru Forum > Наш форум > Технические вопросы > C++ и виртуальное наследование
Грабли №100500
Версия для печати | Отправить тему по E-Mail | Подписаться на эту тему

Быстрый переход:
Оцените эту тему:

Правила Форума:
Вы not можете создавать новые темы
Вы not можете отвечать в темы
Вы not можете прикреплять вложения
Вы not можете редактировать ваши сообщения
HTML Код ВЫКЛ
vB Код ВКЛ
Смайлики ВКЛ
[IMG] Код ВКЛ
 

< Обратная связь - HLFX.ru >

На основе vBulletin
Авторское право © 2000 - 2002, Jelsoft Enterprises Limited.
Дизайн и программирование: Crystice Softworks © 2005 - 2024