财经资讯网站该怎么做推广,后台做网站的题,网上购物哪家质量好,德州极速网站建设 小程序一、为什么基类中的析构函数要声明为虚析构函数#xff1f; 直接的讲#xff0c;C中基类采用virtual虚析构函数是为了防止内存泄漏。具体地说#xff0c;如果派生类中申请了内存空间#xff0c;并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数 直接的讲C中基类采用virtual虚析构函数是为了防止内存泄漏。具体地说如果派生类中申请了内存空间并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数当删除基类指针指向的派生类对象时就不会触发动态绑定因而只会调用基类的析构函数而不会调用派生类的析构函数。那么在这种情况下派生类中申请的空间就得不到释放从而产生内存泄漏。所以为了防止这种情况的发生C中基类的析构函数应采用virtual虚析构函数。 1. 测试代码
#include iostream
#include memory
using namespace std;class Base {
public:Base() { cout Base Constructor endl; }~Base() { cout Base Destructor endl; }
};class Derived : public Base {
public:Derived() { cout Derived Constructor endl; }~Derived() { cout Derived Destructor endl; }
};int main()
{Base* p new Derived();delete p;return 0;
}
输出结果 2. 测试代码
#include iostream
#include memory
using namespace std;class Base {
public:Base() { cout Base Constructor endl; }virtual ~Base() { cout Base Destructor endl; }
};class Derived : public Base {
public:Derived() { cout Derived Constructor endl; }virtual ~Derived() { cout Derived Destructor endl; }
};int main()
{Base* p new Derived();delete p;return 0;
}
输出结果 二、构造函数可以调用虚函数吗语法上通过吗语义上可以通过吗
#includestring
#includeiostream
using namespace std;class B {
public:B(const string ss) { cout B constructor\n; f(ss); }virtual void f(const string) { cout B::f\n; }
};class D : public B {
public:D(const string ss) :B(ss) { cout D constructor\n; }void f(const string ss) { cout D::f\n; s ss; }
private:string s;
};int main()
{D d(Hello);
}
输出结果 分析 注意输出不是D::f 。 究竟发生了什么f()是在B::B()中调用的。如果构造函数中调用虚函数的规则不是如前文所述那样
而是如一些人希望的那样去调用D::f()。那么因为构造函数D::D()尚未运行字符串s还未初始化所以当D::f()试图将参数
赋给s时结果多半是——立马当机。 析构则正相反遵循从继承类到基类的顺序拆房子总得从上往下拆吧所以其调用虚函数的行为和在构造函数中一样虚函数此时此刻被绑定到哪里当然应该是基类啦——因为继承类已经被“拆”了——析构了调用的就是哪个函数。 有时这条规则被解释为是由于编译器的实作造成的。[译注从实作角度可以这样解释在许多编译器中直到构造函数调用完毕vtable才被建立此时虚函数才被动态绑定至继承类的同名函数。] 但事实上不是这么一回事——让编译器实作成“构造函数中调用虚函数也和从其他函数中调用一样”是很简单的[译注只要把vtable的建立移至构造函数调用之前即可]。关键还在于语言设计时的考量——让虚函数可以求助于基类提供的通用代码。[译注先有鸡还是先有蛋Bjarne实际上是在告诉你不是“先有实作再有规则”而是“如此实作因为规则如此”。]