我在运行以下代码时遇到了一个奇怪的现象:
#include <iostream>
class Piece {
public:
class Queen;
class Knight;
union Any;
virtual const char* name() const = 0;
};
class Piece::Queen : public Piece {
public:
virtual const char* name() const {
return "Queen";
}
};
class Piece::Knight : public Piece {
public:
virtual const char* name() const {
return "Knight";
}
};
union Piece::Any {
public:
Any() {}
Piece::Queen queen;
Piece::Knight knight;
};
using namespace std;
int main(int argc, const char* argv[]) {
Piece::Any any;
any.queen = Piece::Queen();
cout << any.queen.name() << endl;
return 0;
}
程序在Apple LLVM 3.0编译器上成功编译,但输出是&#34; Knight&#34;。 我期待输出是&#34; Queen&#34;。 从我的测试中我看到,当Piece :: Any的默认构造函数运行时,它会调用Piece :: Queen和Piece :: Knights&#39;建设者,一个接一个。如果我要声明片段::任何像这样:
union Piece::Any {
public:
Any() {}
Piece::Knight knight;
Piece::Queen queen;
};
(我基本上交换了骑士和女王的顺序)然后输出将是女王。 任何帮助将不胜感激。
由于
答案 0 :(得分:4)
首先 - 你的构造函数似乎没有初始化它的成员。你应该选择一个,例如
Piece::Any::Any(): knight() {}
然后根据9.5.4
通常,必须使用显式析构函数调用和放置新运算符来更改联合的活动成员
所以从骑士到女王的正确切换是
any.knight.~Knight();
new(&any.queen) Queen;
如果它对你来说看起来很难看(就像它对我一样),很清楚地表明,保持带有非平凡构造函数的对象并不是一个好主意(boost :: variant怎么样?)。
答案 1 :(得分:3)
any.queen = Piece::Queen();
这并不意味着你的想法。这相当于
any.queen.operator=(Piece::Queen());
如果any.queen
不存在,则无法可靠地工作(因为您没有强制union
包含活动成员)。
您需要实际初始化您要使用的成员,例如:
new (&any.queen) Piece::Queen;