4

我正在尝试了解虚拟析构函数。以下是此页面的复制粘贴何时使用虚拟析构函数?

在这里,您会注意到我没有将 Base 的析构函数声明为虚拟的。现在,让我们看一下以下代码段:

Base *b = new Derived(); // use b 
delete b; // Here's the problem!

[...]如果您想通过基类指针防止删除实例,您可以使基类析构函数受保护且非虚拟;通过这样做,编译器不会让您在基类指针上调用 delete。

我不明白为什么通过使用受保护的非虚拟基类析构函数来防止删除。编译器不认为我们正在尝试delete从基类对象调用吗?和那有什么protected关系?

4

3 回答 3

11

C++ 标准有这样的说法delete(第 5.3.5p10 节):

释放函数和析构函数(12.4、12.5)都进行了访问和歧义控制。

因此,只有有权访问析构函数的代码才能使用delete. 由于析构函数是protected,这意味着没有人可以调用delete类型的指针Base*。只有子类才能使用析构函数(唯一可以使用的是子类自己的析构函数,作为子对象销毁过程的一部分)。

当然,子类应该有自己的析构函数public,允许你通过子类类型删除对象(假设是正确的实际类型)。

注意:实际上,其他成员Base可以这样做,delete (Base*)p;因为他们有权访问。但是 C++ 假定使用这种结构的人不会这样做——C++ 访问控制只为您的类之外的代码提供指导。

于 2013-10-25T01:12:36.307 回答
6

delete b;有效地执行b->~Base(); deallocate(b);。第一部分 - 调用析构函数 - 如果析构函数不可访问(与调用任何其他不可访问方法失败的方式相同),将无法编译。

于 2013-10-25T01:12:10.833 回答
0

根据我的理解(基于this page),我们想在基类中使用非虚拟和受保护的析构函数的唯一情况如下:

#include <iostream>

struct unary_function {
protected:
  ~unary_function() {
      std::cout << "unary_function" << std::endl;
  }
};

struct IsOdd : public unary_function {
public:
    bool operator()(int number) { 
        return (number % 2 != 0); 
    }
};

void f(unary_function *f) {
  // compile error
  // delete f;
}

int main() {
  // unary_function *a = new IsOdd;
  // delete a;

  IsOdd *a = new IsOdd;
  delete a;

  getchar();
  return 0;
}

因此,您只能这样做:

  IsOdd *a = new IsOdd;
  delete a;

或者

  IsOdd c;

从来没有这些:

  unary_function *a = new IsOdd;
  delete a;

因此,对于非虚拟受保护的析构函数,当您尝试使用它时编译器会给出错误

void f(unary_function *f) {
  delete f; 
  // this function couldn't get compiled because of this delete. 
  // you would have to use the derived class as the parameter 
}
于 2016-12-09T19:23:06.747 回答