问题
I came across a strange phenomena upon running the following code:
#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;
}
The program compiled successfully on the Apple LLVM 3.0 compiler, but the output was "Knight". I was expecting for the output to be "Queen". From my testing I saw that when Piece::Any's default constructor runs, it calls both Piece::Queen and Piece::Knights' constructors, one after another. If I were to declare Piece::Any like this:
union Piece::Any {
public:
Any() {}
Piece::Knight knight;
Piece::Queen queen;
};
(I basically swapped the order of knight and queen) then the output would be Queen. Any help would be appreciated.
Thanks
回答1:
First of all - your constructor seems to initialize none of its members. You should choose one, for example
Piece::Any::Any(): knight() {}
Then according to 9.5.4
In general, one must use explicit destructor calls and placement new operators to change the active member of a union
so correct switching from knight to queen is
any.knight.~Knight();
new(&any.queen) Queen;
If it looks ugly to you (as it does to me), it is clear indication, that keeping objects with non-trivial constructors in union is not a good idea (how about boost::variant?).
回答2:
any.queen = Piece::Queen();
This does not mean what you think it does. This is equivalent to
any.queen.operator=(Piece::Queen());
which cannot reliably work if any.queen
does not exist (because you haven't forced your union
to contain an active member).
You need to actually initialise the member you want to use, for example like this:
new (&any.queen) Piece::Queen;
来源:https://stackoverflow.com/questions/9546914/c-union-containing-class-instances-calls-wrong-virtual-function