Использование объединения внутри класса

Я видел код следующим образом:

class A 
{
private:
    union {
        B *rep;
        A *next;
    }; // no variables of this anonymous defined!

    void func()
    {
        A *p = new A;

        p->next = NULL; // why p has a member variable of 'next'?
    }
};

Я скомпилировал вышеуказанный код с VS2010 без каких-либо ошибок. Вот вопрос:

почему p имеет переменную-член 'next'?

    union {
        B *rep;
        A *next;
    };

Насколько я знаю, это анонимный союз, даже не определяющий переменную. Как мы можем получить доступ к переменным-членам внутри этого объединения?

Ответ 1

Поскольку это в значительной степени то, что делает анонимный союз, оно определяет переменные с нулевым или большим числом в охватывающем пространстве имен (которое в объявлении класса делает им имена полей), которые занимают перекрывающуюся память. Следовательно, он используется так же, как если бы вы объявили

class A 
{
private:
    B *rep;
    A *next;

    void func()
    {
        A *p = new A;

        p->next = NULL;
    }
};

... за исключением rep и следующего занимающего перекрывающегося пространства (или учитывая, что два указателя будут иметь одинаковый размер, одно и то же пространство) и, следовательно, все опасности и преимущества, которые приходят с именованным объединением.

Ответ 2

Здесь приведена цитата из стандарта, который контролирует это поведение: раздел [class.union] (формулировка из С++ 0x draft n3242)

Объединение вида union { спецификация участника } ; называется анонимным объединением; он определяет неназванный объект неназванного типа. Спецификация участника анонимного объединения определяет только нестатические элементы данных. [Примечание. Вложенные типы и функции не могут быть объявлены в анонимном объединении. - конец примечания] Имена членов анонимного союза должны отличаться от имен любого другого объекта в области, в которой объявлен анонимный союз. Для целей поиска имени, после определения анонимного союза, члены анонимного объединения считаются определенными в области, в которой объявлен анонимный союз.

Ответ 3

Я не уверен, что понимаю ваш вопрос.

A имеет член p, потому что вы объявили его в внутри анонимного объединения вместе с rep.

Вы объявили переменную! Это просто, что "rep" и "next" используют одну и ту же память.

Вы можете получить к нему доступ так же, как и вы.

Анонимные союзы

(как и структуры) помещают их члены в то же пространство имен, что и указанное пространство имен.

Это полезно для, например:

union W00t {
    struct {
         uint32_t a,b;
    };
    struct {
         uint64_t c;
    };
 }

Ответ 4

Я удивлен, что есть современный компилятор, который до сих пор позволяет эту конструкцию. Это один из первых дней C, около 1975 года. В те дни структура и члены профсоюза фактически не были привязаны к определенной структуре, но содержали в качестве атрибутов смещение от базового адреса и типа данных.

Конечным результатом было то, что использование структуры или объединения правильно приводит к правильному коду с выражениями, оцененными как ожидалось. Единственное различие заключается в том, что неправильное использование элемента структуры с указателем, не связанным с типом, не будет помечено как ошибка. Я не думаю, что была какая-то особая причина для того, чтобы не навязывать подсказку ассоциированного-K & R, что будущие компиляторы, надеюсь, будут проверять такие виды использования - возможно, просто сохранить табличное пространство символов в 16-битной стране.