zoukankan      html  css  js  c++  java
  • C++ 构造函数和析构函数的调用顺序、虚析构函数的作用

    构造函数和析构函数的调用顺序

    构造函数的调用顺序:

    当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达最底层的目标派生类的构造函数为止。

    析构函数的调用书序:

    当删除一个对象时,首先调用该派生类的析构函数,然后调用上一层基类的析构函数,依次类推,直到到达最顶层的基类的析构函数为止。

    简单的说,构造函数是“自上向下”调用,析构函数是“自下而上”调用。

    演示代码如下:

    #include<iostream>
    using namespace std;
    
    class Base{
    public:
    	Base(){cout<<"创建Base基类。"<<endl;}
    	~Base() {cout<<"删除Base基类。"<<endl;}
    };
    class Child : public Base{
    public:
    	Child() {cout<<"创建Child派生类。"<<endl;}
    	~Child() {cout<<"删除Child派生类。"<<endl;} 
    };
    
    int main()
    {
    	cout<<"*********构造函数调用顺序示例***********"<<endl;
    	Child *C1 = new Child;
    	cout<<"*********析构函数调用顺序示例***********"<<endl;
    	delete C1;
    }
    运行结果如下图:



    虚析构函数的作用

    通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。

    原因:在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。析构函数同样需要如此。

    如果用基类的指针来删除派生类的对象,而这个基类有一个非虚的析构函数,则结果是未定义的。后果是对象的派生部分不会被销毁,然而,基类部分很可能已被销毁,这就导致产生了“部分析构”的情况,这是一个内存泄露

    可以通过如下代码来说明:

    #include<iostream>
    using namespace std;
    
    class Base{
    public:
    	Base(){cout<<"创建Base基类。"<<endl;}
    	~Base() {cout<<"删除Base基类。"<<endl;}	/*非虚析构函数*/
    };
    class Child : public Base{
    public:
    	Child() {cout<<"创建Child派生类。"<<endl;}
    	~Child() {cout<<"删除Child派生类。"<<endl;} 
    };
    
    int main()
    {
    	cout<<"*********非虚析构函数调用示例***********"<<endl;
    	Base *C1 = new Child;
    	delete C1;
    }
    运行结果如下,此时删除C1指针时,只调用了Base类的析构函数,没有调用Child类的析构函数。


    当更改Base基类的析构函数为虚函数时,代码如下:

    #include<iostream>
    using namespace std;
    
    class Base{
    public:
    	Base(){cout<<"创建Base基类。"<<endl;}
    	virtual ~Base() {cout<<"删除Base基类。"<<endl;}	/*虚析构函数*/
    };
    class Child : public Base{
    public:
    	Child() {cout<<"创建Child派生类。"<<endl;}
    	~Child() {cout<<"删除Child派生类。"<<endl;} 
    };
    
    int main()
    {
    	cout<<"*********虚析构函数调用示例***********"<<endl;
    	Base *C1 = new Child;
    	delete C1;
    }
    此时运行结果如下,先调用了Child派生类的析构函数,再调用了Base基类的析构函数。



    但是,一般如果不做基类的类的析构函数一般不声明为虚函数,因为虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数。典型情况下,这一信息具有一种被称为 vptr(virtual table pointer,虚函数表指针)的指针的形式。vptr 指向一个被称为 vtbl(virtual table,虚函数表)的函数指针数组,每一个包含虚函数的类都关联到 vtbl。当一个对象调用了虚函数,实际的被调用函数通过下面的步骤确定:找到对象的 vptr 指向的 vtbl,然后在 vtbl 中寻找合适的函数指针。这样子会使类所占用的内存增加。


  • 相关阅读:
    Oracle11g工具
    Oracle数据库中scott用户的所有表结构
    Oracle数据库手动解锁scott用户
    Oracle数据库实例的删除和安装
    Oracle数据库的安装
    Oracle数据库发展历史
    禁止浏览器中双击选中元素的解决方法
    Window 设置pm2开机自启动服务
    通过node创建web服务器----express插件打包上线
    vue项目优化----通过externals加载外部CDN资源
  • 原文地址:https://www.cnblogs.com/fengty90/p/3768848.html
Copyright © 2011-2022 走看看