C++ 基类中受保护的非虚拟析构函数

C++ 基类中受保护的非虚拟析构函数,c++,protected,virtual-destructor,C++,Protected,Virtual Destructor,我试图理解虚拟析构函数。以下是此页面的复制粘贴 在这里,您会注意到我并没有声明Base的析构函数为 事实上的现在,让我们看一下以下代码片段: Base *b = new Derived(); // use b delete b; // Here's the problem! […]如果要防止通过基类指针删除实例,可以使基类析构函数受保护且非虚拟;这样,编译器就不允许您对基类指针调用delete 我不明白为什么使用受保护的非虚拟基类析构函数来阻止删除。编译器不认为我们试图从基类对象调用dele

我试图理解虚拟析构函数。以下是此页面的复制粘贴

在这里,您会注意到我并没有声明Base的析构函数为 事实上的现在,让我们看一下以下代码片段:

Base *b = new Derived(); // use b 
delete b; // Here's the problem!
[…]如果要防止通过基类指针删除实例,可以使基类析构函数受保护且非虚拟;这样,编译器就不允许您对基类指针调用delete


我不明白为什么使用受保护的非虚拟基类析构函数来阻止删除。编译器不认为我们试图从基类对象调用
delete
?受保护的与此有什么关系?

删除b有效地执行
b->~Base();取消分配(b)。第一部分-调用析构函数——如果不能访问析构函数(编译为调用任何其他不可访问的方法失败),则编译失败。<> P> C++标准有关于“代码>删除<代码> >(5.3.5P10):

解除分配功能和析构函数(12.4、12.5)都进行访问和模糊控制

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

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

注:实际上,
Base
的其他成员可以执行
delete(Base*)p因为他们有访问权限。但是C++假设使用这种构造的人不会做这一点——C++访问控制只对类之外的代码提供指导。
struct unary_function {
  typedef int argument_type;
  typedef bool result_type;

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(int argc, char **argv) {
  // unary_function *a = new IsOdd;
  // delete a;

  IsOdd *a = new IsOdd;
  delete a;

  getchar();
  return 0;
} // main

永远不要忘记这些:

  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 
}

“功能”,谢谢。它不是
virtual
,也不像方法那样调度。@BenVoigt:我不太明白术语“method”在应用于虚拟成员函数时比应用于非虚拟成员函数更合适。我必须承认我没有意识到其中的差别。我能理解的是,C++中没有任何方法,只有成员函数(虽然我认为它可能是过于迂腐的)。但我不理解这个特殊的划分。@BenVoigt:一个权威人士甚至将“方法”定义为“与类关联的子例程(或过程)”,甚至还谈到“虚拟方法”和“非虚拟方法”。我的情况到此为止。没有方法,只有成员函数。但虚拟成员函数可以像方法一样进行调度。(“方法”是在OOP理论中定义的,肯定涉及到分派。想想“多方法”的扩展情况。)@BenVoigt:Java有静态方法。这些是“派遣”的吗?我怀疑,即使曾经对“方法”一词有过严格的定义,按照你坚持的思路,口语使用也已经大大偏离了这种定义,无论是好是坏。
  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 
}