【问题标题】:C++ initializer lists with unions, why different results?带有联合的 C++ 初始化程序列表,为什么不同的结果?
【发布时间】:2012-01-12 15:42:52
【问题描述】:

我有以下程序:

#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 的泛型方法。这是为什么?我尝试了带有选项-std=c++0x 的 gcc 4.6,以防万一。

【问题讨论】:

    标签: c++ pointers initialization virtual unions


    【解决方案1】:

    联合只能与 POD 类型一起使用,因此不能有具有虚函数或非平凡构造函数/析构函数的成员,因此这是未定义的行为。阅读(取自this answer)标准的§9.5.1:

    联合可以有成员函数(包括构造函数和 析构函数),但不是虚函数。工会不应有基地 类。联合不应用作基类。一个对象 具有非平凡构造函数、非平凡复制构造函数的类, 一个重要的析构函数,或一个重要的复制赋值运算符 不能是联合的成员,也不能是此类对象的数组。如果一个 union 包含一个静态数据成员,或者一个引用类型的成员, 程序格式不正确。

    在某些情况下,C++ 只允许使用 POD 类型。为了 例如,C++ 中的 union 不能包含具有 virtual 的类 函数,或非平凡的构造函数或析构函数。这个限制 强加是因为编译器无法知道哪个构造函数或 应该为联合调用析构函数。

    【讨论】:

    • 那不是 C++03 吗? IIRC,C++11 允许具有非平凡 ctor 和 dtor 的类型。
    • C++11 中似乎不再有限制。 Gcc 根本不编译代码,如果没有 -std=c++0x 标志,则抱怨不允许具有构造函数的类。有了标志,它甚至不会发出警告。
    • @Xeo,Juho Ah,然后只考虑这个答案 C++03。在 C++11 中,它是否还允许您与具有虚函数的成员建立联合?
    • 我不知道OTOH,而且我目前手边没有标准。
    • 程序可能由于其他原因未定义。它检查联合的 nihi 字段,而实际上分配了其他字段。该标准将允许检查联合的“标准布局”结构成员的常见初始字段。具有虚函数的类不是“标准布局”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-09
    • 1970-01-01
    • 2021-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多