C ++析构函数行为

时间:2009-12-20 22:53:57

标签: c++ inheritance virtual-destructor

我有一个关于C ++析构函数行为的问题,更多的是出于好奇而不是其他任何问题。我有以下课程:

Base.h

class BaseB;

class BaseA
{
    public:
        virtual int MethodA(BaseB *param1) = 0;
};

class BaseB
{
};

Imp.h

#include "Base.h"
#include <string>

class BImp;

class AImp : public BaseA
{
    public:
        AImp();
        virtual ~AImp();

    private:
        AImp(const AImp&);
        AImp& operator= (const AImp&);

    public:
        int MethodA(BaseB *param1) { return MethodA(reinterpret_cast<BImp *>(param1)); }

    private:
        int MethodA(BImp *param1);
};

class BImp : public BaseB
{
    public:
        BImp(std::string data1, std::string data2) : m_data1(data1), m_data2(data2) { }
        ~BImp();
        std::string m_data1;
        std::string m_data2;

    private:
        BImp();
        BImp(const BImp&);
        BImp& operator= (const BImp&);
};

现在,问题在于使用此代码,一切都可以正常运行。但是,当我为BImp虚拟构建析构函数时,在调用AImp :: MethodA时,类BImp似乎没有初始化其数据(m_data1和m_data2)。我已经检查并确保所包含的数据在施工时是正确的,所以我想知道这背后的原因是什么......

干杯!

编辑:param1实际上是MethodA中对B的引用。看起来我过度清理了我的真实代码!

编辑2:重新排列代码以显示两个不同的文件。测试了这段代码编译好了。对此感到抱歉!

5 个答案:

答案 0 :(得分:9)

如果您在相关类型之间进行转换,就像在这种情况下那样you should use static_cast or dynamic_cast,而不是reinterpret_cast,因为编译器可能在投射时调整对象指针值更多派生类型。在这种情况下,reinterpret_cast的结果是未定义的,因为它只取指针值并假装它是另一个对象,而不考虑对象布局。

答案 1 :(得分:2)

MethodA按值获取其参数。这意味着传递副本(并且必须销毁副本)。这是我最好的猜测,为什么你可能有一个你没想到的BImpl被摧毁,但我不知道A的析构函数的虚拟或非虚拟性质可能与它有什么关系。

但是这段代码无法编译 - 你在B中声明虚函数时使用了B类,但是直到稍后才定义B.而且我不知道该演员会发生了什么 - 你无法重新解释播放类类型。也许如果你编写一个演示你的问题的测试用例,并发布它?

答案 2 :(得分:1)

这段代码中有很多不确定的东西,所以我很惊讶它在任何情况下都可以工作或编译。

  • 按值传递参数而不是参考MethodA
  • 通过BBImp投放到reinterpret_cast - 糟糕的主意!如果您要向这个方向投掷,dynamic_cast是最安全的。
  • 我没有看到你应该如何从B中获取BImp。你没有调用任何构造函数,并且你没有可以调用它来接受B.你的BImp的默认构造函数是私有的,并且将没有数据的B分配给仍然没有数据的BImp到BImp,仍然不会给你任何数据!

答案 3 :(得分:1)

几条评论:

  • 您的基类应该具有虚拟析构函数,因此在删除对象时,将调用派生类'dtor而不是基类dtor。

  • MethodA将BaseB指针作为参数仅将指针重新解释为BImp(BaseB的派生类)是危险的。除了将BImp传递给MethodA之外,无法保证其他内容。如果只有一个BaseB对象是MethodA会发生什么?我怀疑可能会有很多不好的事情。

  • 我猜你的代码“完美无缺”,因为你只将BImp传递给MethodA。如果您只是将BImp传递给MethodA,那么使签名与intent相匹配(这具有删除该可怕的重新解释调用的额外好处)。

答案 4 :(得分:0)

您的代码格式错误。它不是有效的C ++。在C ++语言中,reinterpret_cast只能用于在指针类型,引用类型之间进行转换,以执行指针到整数的转换(在任一方向上)。

在您的代码中,您尝试使用reinterpret_castB类型转换为BImp类型。这在C ++中显然是非法的。如果您的编译器允许使用此代码,则必须查阅编译器的文档以确定正在进行的操作。

其他回复已经提到过“切片”。请记住,这只是对特定编译器的特定非标准行为的猜测。它与C ++语言无关。