Использование объединения внутри класса
Я видел код следующим образом:
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-битной стране.