Виртуальные таблицы на анонимных классах
В моем коде есть что-то похожее:
#include <iostream>
#include <cstdlib>
struct Base
{
virtual int Virtual() = 0;
};
struct Child
{
struct : public Base
{
virtual int Virtual() { return 1; }
} First;
struct : public Base
{
virtual int Virtual() { return 2; }
} Second;
};
int main()
{
Child child;
printf("ble: %i\n", ((Base*)&child.First)->Virtual());
printf("ble: %i\n", ((Base*)&child.Second)->Virtual());
system("PAUSE");
return 0;
}
Я ожидаю, что это даст этот результат:
ble: 1
ble: 2
и он делает это, когда компилируется в GCC (3.4.5, я считаю).
Компиляция и запуск этого в Visual Studio 2008, однако, дает следующее:
ble: 2
ble: 2
Интересно, что если я даю имена структурных производных Base (struct s1 : public Base
), он работает правильно.
Какое поведение, если оно есть, является правильным? Является ли VS просто причудливым, или он придерживается стандарта? Я пропустил что-то жизненно важное здесь?
Ответы
Ответ 1
Видно, как MSVC неправильно воспринимает символы отладки. Он генерирует временные имена для анонимных структур, соответственно Child::<unnamed-type-First>
и Child::<unnamed-type-Second>
. Однако есть только одна таблица vtable, она называется Child::<unnamed-tag>::'vftable'
, и оба конструктора используют ее. Различное имя для vtable, безусловно, является частью ошибки.
На сайте connection.microsoft.com сообщается о нескольких ошибках, связанных с анонимными типами, но ни один из них никогда не делал его "обязательным". Не тот, который ты нашел, афайк. Возможно, обходной путь слишком прост.
Ответ 2
Похоже, что это ошибка в VS 2008, возможно, потому что она перезаписывает или игнорирует vtable для первого неназванного класса в пользу vtable для второго, поскольку внутренние имена идентичны. (Когда вы укажете одно явно, внутренние имена для vtables больше не идентичны.)
Насколько я могу судить по стандарту, это должно работать так, как вы ожидаете, и gcc прав.
Ответ 3
Я могу подтвердить, что это известная ошибка в компиляторе VC (и это repos в VC10); два анонимных класса неправильно используют vtable.
Анонимные структуры - это не часть стандарта С++.
Изменить. Анонимные структуры - это разногласия. Это может означать две вещи:
class outer
{
public:
struct {
int a;
int b;
} m_a; // 1
struct {
int c;
}; // 2
union {
int d;
int e;
}; // 3
};
1 это то, что здесь происходит, лучшим именем, чем анонимная структура, будет "неназванная структура". Сам тип структуры не имеет имени, но объект делает (m_a).
2 также известен как анонимная структура и не является законным С++. Нет имени объекта, и идея в том, что вы можете получить доступ к полю 'c' непосредственно на объектах типа external. Это компилируется только из-за расширения компилятора в Visual Studio (не будет выполнено под /Za )
3 Анонимные союзы, напротив, являются законными С++.
Я смутил их, потому что здесь мы называем # 1 "анонимной структурой", а провода в моем мозгу пересекаются с № 2.