[英]base class 'class std::vector<…>' has a non-virtual destructor
[英]Protected non-virtual destructor in the base class
我正在尝试了解虚拟析构函数。 以下是此页面的复制粘贴何时使用虚拟析构函数?
在这里,您会注意到我没有将 Base 的析构函数声明为虚拟的。 现在,让我们看一下以下代码段:
Base *b = new Derived(); // use b delete b; // Here's the problem!
[...] 如果要防止通过基类指针删除实例,可以使基类析构函数受保护且非虚拟; 通过这样做,编译器不会让您在基类指针上调用 delete。
我不明白为什么通过使用受保护的非虚拟基类析构函数来防止删除。 编译器不认为我们正在尝试从基类对象中调用delete
吗? protected
与此有什么关系?
C++ 标准对delete
有这样的说法(第 5.3.5p10 节):
释放函数和析构函数(12.4、12.5)都进行了访问和歧义控制。
因此,只有有权访问析构函数的代码才能使用delete
。 由于析构函数是protected
,这意味着没有人可以对Base*
类型的指针调用delete
。 只有子类才能使用析构函数(唯一可以使用的是子类自己的析构函数,作为子对象销毁过程的一部分)。
当然,子类应该使自己的析构函数public
,允许您通过子类类型删除对象(假设是正确的实际类型)。
注意:实际上, Base
的其他成员可以delete (Base*)p;
因为他们有访问权限。 但是 C++ 假定使用这种结构的人不会这样做——C++ 访问控制只为您的类之外的代码提供指导。
delete b;
有效地执行b->~Base(); deallocate(b);
b->~Base(); deallocate(b);
. 第一部分 - 调用析构函数 - 如果析构函数不可访问(与调用任何其他不可访问方法失败的方式相同),则将无法编译。
据我了解(基于此页面),我们想在基类中使用非虚拟和受保护的析构函数的唯一情况如下:
#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
}
类的受保护方法和变量(我们称之为Base
)只能由派生类访问。 因此,如果您在派生类之外对Base
类型的指针调用delete
,它将尝试调用Base::~Base()
(Base 的析构函数),但由于它是受保护的,因此无法调用它,从而导致编译错误。
根据规范,基类的析构函数只能声明为 protected 和 non-virtual(不允许通过Base
指针删除派生对象),或 public 和 virtual(允许通过Base
指针)。
如果析构函数被声明为公共的和非虚拟的,那么如果指向派生类的 Base 类型的指针被删除,则会导致未定义的行为。
两个选项:
Derived
的Base
指针:class Base {
public:
Base() {
std::cout << "Base ctor called.\n";
}
protected:
~Base() {
std::cout << "Base dtor called.\n";
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived ctor called.\n";
}
~Derived() {
std::cout << "Derived dtor called.\n";
}
};
Base *foo = new Derived;
delete foo; // compilation error
...如您的问题中所述。
Derived
对象的Base
类型的指针。 首先调用Derived
析构函数,然后调用Base
析构函数:class Base {
public:
Base() {
std::cout << "Base ctor called.\n";
}
virtual ~Base() {
std::cout << "Base dtor called.\n";
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived ctor called.\n";
}
~Derived() override {
std::cout << "Derived dtor called.\n";
}
};
Base *foo = new Derived;
delete foo;
输出:
Base ctor called.
Derived ctor called.
Derived dtor called.
Base dtor called.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.