Подтвердить что ты не робот

Виртуальные таблицы на анонимных классах

В моем коде есть что-то похожее:

#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 просто причудливым, или он придерживается стандарта? Я пропустил что-то жизненно важное здесь?

4b9b3361

Ответ 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.