如果作为基类型引用传递,派生类型是否解构?

时间:2012-10-09 14:09:22

标签: c++ inheritance pass-by-reference destructor

我有一个Base类,它被认为是只读的,并且在它的虚拟析构函数中它什么都不做。 现在我将Base类派生为Derived类,它是可写的,并且在它的析构函数中,它删除了Base成员:

class Base
{
    virtual ~Base() {}
    void* Data;
}
class Derive : public virtual Base
{
    virtual ~Derive() { delete Data; }
}

忽略上面的语法错误代码,如果我将Derive实例传递给一个以Base类作为参考的Function:

void Function(const Base& base)
{
   ...
}

...
Derive der = Derive();
...
Function(der);

在函数范围的末尾是否会调用派生的析构函数?我很难找到合适的关键字来找到答案,所以如果之前有人问过我,我很抱歉。我假设C ++对于它们的类型处理引用而不是它们可能的类型,但我可能是错的。

2 个答案:

答案 0 :(得分:3)

不,它不会,因为对象不会超出范围。它超出范围,并在调用Function后自动销毁。

{
  Derive der = Derive();
  //...
  Function(der);
  //...
  //der still alive here
} //der is destroyed here, all destructors are called correctly

如果您要传递参数按值而不是参考:

void Function(Base base)
{
   ...
}

对象将切片。在Function内创建的副本是Base类型的对象(不是Derive),因此当函数退出时,只会调用Base析构函数。

答案 1 :(得分:0)

  

派生的析构函数是否会在函数作用域的末尾被调用?

没有。当对象本身而不是对它的引用超出范围时,将调用派生的析构函数。引用不是对象。这只是一个别名。或者,将引用视为不能为null的指针,不能重新分配,并使用.来访问成员而不是->。除此之外,他们只是指针。当您将指针传递给函数时,仅仅因为指针在函数结束时超出范围并不意味着指向的对象超出范围。这同样适用于参考文献。

你的设计有点时髦。一些问题:

  • 班级void*中的Base数据成员有什么用?
  • 为什么void*指针?这有点C而不是C ++。
  • Base中的任何成员函数是否都使用该数据成员?
    • 如果没有,为什么该数据成员是该类的一部分?
  • ~Derive()删除此内容而不是~Base(),这有点令人怀疑。这个设计背后的理由是什么?