为什么派生类的析构函数是在对基类的const引用上调用的?

时间:2011-02-13 17:49:46

标签: c++ inheritance reference

GMan's answer here中,restore_base类的析构函数不是virtual,所以我一直想知道它是如何工作的。通常,您希望在对象超出范围之后仅执行restorer_base的析构函数,但似乎实际调用了派生的restorer_holder析构函数。有人想开导我吗?

1 个答案:

答案 0 :(得分:18)

需要虚拟析构函数的标准情况是

void foo()
{
   scoped_ptr<Base> obj = factory_returns_a_Derived();

   // ... use 'obj' here ...
}

的标准情况是

void foo()
{
   Derived obj;

   // ... use 'obj' here ...
}

GMan的代码做了一些有点棘手的事情,结果证明与第二种情况相同:

void foo()
{
   Base& obj = Derived();

   // ... use 'obj' here ...
}

obj是一个简单的参考;通常,它根本不会触发析构函数。但它是从一个匿名临时对象初始化的,其静态类型 - 编译器已知 - 为Derived。当该对象的生命周期结束时,编译器将调用Derived析构函数。通常,匿名临时对象会在创建它的表达式的末尾消亡,但临时对象初始化引用有一个特殊情况:它们一直存在,直到引用本身死亡,这是范围的结束。所以你得到伪 - scoped_ptr行为,你不需要虚拟析构函数。

编辑:由于现在已经出现过两次:参考必须为const才能应用此特殊规则。 C + 98 [class.temporary] / 5:

  

第二个上下文[其中临时对象在其末尾未被销毁   full-expression]是引用绑定到临时的时候。临时到哪   引用是绑定的,也可以是作为子对象的完整对象的临时对象   临时绑定的内容在参考的生命周期 ...

中持续存在

强调我的。此语言中未提及const,因此引用不必是const

编辑2:标准中的其他规则禁止为非左值的临时对象创建非常量引用。我怀疑至少有一些临时对象左值,但我不确定。无论如何,不会影响此规则。对于临时对象的非常量引用延长其生命周期仍然是正式的,即使没有严格符合C ++程序也无法创建这样的引用。这可能看起来很荒谬,但你应该从字面上和迂腐地阅读这个标准。每个单词都很重要,每个单词都不重要。