dynamic_cast завершается неудачно — в зависимости от версии ОС

У меня есть динамический состав, который терпит неудачу. Расположение классов выглядит так:

class A1
{
public:
virtual int foo1()=0;
};

class A2
{
public:
virtual int foo2();
};

class A3
{
public:
virtual int foo3();
};

class B : public A1, public A2, public A3
{
int bar();
};

Теперь я использую указатели (так что никакое нарезание не может произойти) для снижения.

main()
{
B b;

A1* a1 = dynamic_cast<A1*> (&b); // ok
B*  b1 = dynamic_cast<B*>  (a1); // ok

A2* a2_1 = dynamic_cast<A2*> (a1); // OSX 10.7 ok, OSX 10.9 fail
A2* a1_2 = dynamic_cast<A2*> (b1); // ok

};

Downcast работает, upcast работает, но sidecast не работает всегда. В OSX 10.7 Sidecast работает, в OSX 10.9 — нет (GCC 4.2 использует динамический c ++ stdlib). Глядя на vtable с помощью gdb, я ясно вижу перечисленные методы и члены A2.

Мои вопросы:

а) Является ли Sidecast технически правильным? Должно ли это работать или это ошибка времени выполнения?
б) Если побочная трансляция зависит от времени выполнения, где определяется время выполнения? Я всегда думал, что это часть двоичного файла?
в) Как выглядит сбой dynamic_cast (при просмотре сборки), и как вы можете отследить такие проблемы?

Обновление: это то, что я вижу в системной консоли

01.11.15 14: 16: 27,435 APPNAMECHANGED [15280]: ошибка dynamic_cast 1: Обе из следующих type_info должны иметь публичную видимость. По крайней мере, один из них скрыт. 10А1, 15А2.

Итак, в) ответили, по крайней мере, для OSX 10.9. Посмотрите на консоль. (Linux, кто-то?)
Похоже, проблема с видимостью символа. Док говорит (gcc.gnu.org/wiki/Visibility)

Тем не менее, это не полная история — это становится сложнее. По умолчанию видимость символа «по умолчанию», но если компоновщик встречает только одно определение со скрытым — только одно — этот символ typeinfo становится постоянно скрытым (помните ODR стандарта C ++ — правило одного определения). Это верно для всех символов, но, скорее всего, повлияет на вас с помощью typeinfos; Символы typeinfo для классов без vtable определяются по требованию в каждом объектном файле, который использует класс для EH, и определяются слабо, поэтому определения объединяются во время ссылки в одну копию.

Это приводит к следующему вопросу,

г) как мы можем отследить, какой символ хотя бы раз отмечен как скрытый, и где и почему? Есть ли инструмент для проверки .o файлов?

4

Решение

Отказ от ответственности: я только собираюсь ответить на вопрос а).

Прежде всего, B это явно полиморфный тип в соответствии с [class.virtual] / 1, поскольку он наследует виртуальную функцию (если быть точным, B наследует три отдельных).
Теперь рассмотрим [expr.dynamic.cast] / 8:

Если C это тип класса, к которому T указывает или ссылается, время выполнения
Проверка логически выполняется следующим образом:

  • Если в наиболее производном объекте, на который указывает (указано) значение v, то v указывает (указывает) на открытый базовый класс
    подобъект C объект, и если только один объект типа C происходит от подобъекта
    чтобы по v результат указывает (относится) к этому C объект.
  • Иначе, если v указывает (ссылается) на подобъект общедоступного базового класса самого производного объекта и тип самого производного объекта
    имеет базовый класс, типа Cоднозначно и публично,
    результат указывает (относится) к C подобъект самого производного
    объект.
  • В противном случае проверка во время выполнения терпит неудачу.

Так что да, это должно работать.

0

Другие решения

Эта проблема была окончательно решена после того, как мы обнаружили, что исполняемый файл связан с dylib, который был статически связан со средой выполнения c ++, но был скомпилирован с другим компилятором (gcc 4.8 против clang).

0

По вопросам рекламы [email protected]