【问题标题】:C++: Union containing class instances calls wrong virtual functionC++:包含类实例的联合调用错误的虚函数
【发布时间】:2012-03-21 18:14:29
【问题描述】:

我在运行以下代码时遇到了一个奇怪的现象:

#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 编译器上编译成功,但输出为“Knight”。 我期待输出是“女王”。 从我的测试中我看到当 Piece::Any 的默认构造函数运行时,它会一个接一个地调用 Piece::Queen 和 Piece::Knights 的构造函数。如果我要像这样声明 Piece::Any:

union Piece::Any {
public:
    Any() {}
    Piece::Knight knight;
    Piece::Queen queen;
};

(我基本上交换了骑士和女王的顺序)然后输出将是女王。 任何帮助将不胜感激。

谢谢

【问题讨论】:

    标签: c++ class virtual call unions


    【解决方案1】:

    首先 - 你的构造函数似乎没有初始化它的任何成员。你应该选择一个,例如

    Piece::Any::Any(): knight() {}
    

    那么根据9.5.4

    通常,必须使用显式析构函数调用和放置新运算符来更改联合的活动成员

    从骑士到女王的正确转换是

    any.knight.~Knight();
    new(&any.queen) Queen;
    

    如果它在你看来很难看(就像对我一样),那么很明显,将具有非平凡构造函数的对象保持在联合中并不是一个好主意(boost::variant 怎么样?)。

    【讨论】:

      【解决方案2】:
      any.queen = Piece::Queen();
      

      这并不意味着你认为它会做什么。这相当于

      any.queen.operator=(Piece::Queen());
      

      如果any.queen 不存在(因为您没有强制union 包含活动成员),则无法可靠地工作。

      您需要实际初始化您要使用的成员,例如这样:

      new (&any.queen) Piece::Queen;
      

      【讨论】:

        猜你喜欢
        • 2011-04-12
        • 2018-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多