C ++ инициализатор списки с объединениями, почему разные результаты? - PullRequest
1 голос
/ 12 января 2012

У меня есть следующая программа:

#include <initializer_list>
#include <iostream>

class A;
class nih {
public:
    virtual void apply(A & a) const { std::cout << "generic" << std::endl; };
};

union niit;
class A {
public:
  int s; char kau;
  A() : s(1), kau('-') { }
  A(std::initializer_list<niit> k);
};

class sn : public nih { int s; public: sn(int x) : s(x) { }
  virtual void apply(A & a) const { a.s=s; } };
class kaun : public nih { char kau; public: kaun(char x) : kau(x) { }
  virtual void apply(A & a) const { a.kau=kau; } };
union niit { sn sni; kaun kauni; nih nihi;
  niit(const sn & s) : sni(s) { }
  niit(const kaun & k) : kauni(k) { }
};

A::A(std::initializer_list<niit> k) { 
  const niit *n=k.begin();
  for(int i=0;i<k.size();i++) {
    const nih* p=&n[i].nihi;
    p->apply(*this);
  }
}

int main(int argc, char**argv) {
  A r {kaun('a'),sn(91)};
  std::cout << r.s << r.kau << std::endl;
}

Я получаю ожидаемый результат, который равен 91a. Однако, если я изменю строку

p->apply(*this);

на следующее:

((const nih*)(&n[i].nihi))->apply(*this);

, который должен быть заменен эквивалентным значением, он больше не работает и вместо этого печатает:

generic
generic
0

То есть он выполняет обобщенный метод из nih. Это почему? Я попробовал gcc 4.6 с опцией -std=c++0x, на случай, если это имеет значение.

1 Ответ

2 голосов
/ 12 января 2012

Объединение может использоваться только с типами POD, и поэтому не может иметь членов с виртуальными функциями или нетривиальными конструкторами / деструкторами, так что это неопределенное поведение. Прочитайте (взято из этот ответ ) § 9.5.1 стандарта:

Объединение может иметь функции-члены (включая конструкторы и деструкторы), но не виртуальные функции. У союза не должно быть базы классы. Союз не должен использоваться в качестве базового класса. Объект класс с нетривиальным конструктором, нетривиальным конструктором копирования, нетривиальный деструктор или нетривиальный оператор присваивания копии не может быть членом объединения или массива таких объектов. Если union содержит статический член данных или член ссылочного типа, программа некорректна.

И

В определенных контекстах C ++ допускает использование только типов POD. За Например, объединение в C ++ не может содержать класс, который имеет виртуальный функции, или нетривиальные конструкторы или деструкторы. Это ограничение навязывается, потому что компилятор не может знать, какой конструктор или деструктор должен быть вызван для объединения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...