Вопрос к знатокам теории или тем, кто сталкивался.
Имеем стандартную ситуацию "ромбовидное наследование" с одним хитрым нюансом: клиент библиотеки видит только интерфейсы и не использует RTTI.
Код следующий:
1. Библиотека:
C++ Source Code:
1
// Видимо клиенту
2
class AInterface
3
{
4
public:
5
virtualvoid foo() = 0;
6
};
7
class BInterface : publicvirtual AInterface
8
{
9
public:
10
virtualvoid bar() = 0;
11
};
12
extern"C"__declspec(dllexport) void *get_B();
13
14
// невидимо клиенту
15
class AImplementation : publicvirtual AInterface
16
{
17
public:
18
virtualvoid foo() {};
19
};
20
class BImplementation : public [b][size=4]virtual[/size][/b] BInterface, public AImplementation
При вызове на клиенте b->bar() всё рушится. Если посмотреть в отладчике - выясняется, что таблица виртуальных функций b содержит какую-то иррунду. При этом в библиотеке lib_b содержит эту таблицу правильную.
А дальше всё намного интереснее. Убираем виртуальное наследование от BInterface в библиотеке (я выделил это место), и баг пропадает: даже несмотря на статик_каст, клиентский b содержит правильную таблицу виртуальных функций.
Кто может объяснить это поведение? Насколько оно надёжно? Будет ли это работать в GCC, или это некий благоприятный баг MSVC2010, надеяться на который не стоит?
Добавлено 15-12-2015 в 23:57:
Второй вариант, который работает: слово virtual не трогаем, а меняем сигнатуру у get_B:
Гм, возможно, ломается в более сложных примерах. Там, где и у AImplementation, и у BImplementation есть данные и невиртуальные функции, а также самих виртуальных функций в интерфейсах много. Как у меня и есть в реальном проекте.