精华内容
下载资源
问答
  • 浅析:只能有一个析构函数

    千次阅读 2015-04-01 12:42:11
    的构造函数与析构函数都是与同名(析构函数需要加上'~'),没有返回值的;...但是由于析构函数是没有参数的,那么从而无法通过参数的不同来达到重载多个析构函数的目的,从而析构函数只能有一个。 析构函数是由系

    类的构造函数与析构函数都是与类同名(析构函数需要加上'~'),没有返回值的;而构造函数是可以有参数的,但是析构函数是不能有参数的。

    我们知道类可以有多个构造函数,这些构造函数是重载函数的关系,也就是说函数名都是相同的,区别它们主要靠参数的不同(参数个数和参数类型)。

    但是由于析构函数是没有参数的,那么从而无法通过参数的不同来达到重载多个析构函数的目的,从而析构函数只能有一个。

    析构函数是由系统负责调用的,也可以手工显示调用,但是显示调用析构函数是不会析构该对象的,也就是说显示调用析构函数和没有显示调用析构函数是一样的,

    #include<iostream>
    using namespace std;
    class A
    {
    public:
       A(){};
       void fun() {cout<<"The object exists!";};
       ~A(){};

      int bbb;
    };
    int main()
    {
       A *a=new A();

      a->bbb=345;
       a->~A();//显示调用析构函数后,对象a还存在吗?
       a->fun();
       //编译运行后a->fun()能够输出,对象a仍存在
       return 0;

    再来看看汇编代码

    在VC的DEBUG模式下,通过查看反汇编代码,可以看到,直接调用析构函数的语句没有任何汇编代码对应它,就和没有这一语句一模一样.由此看来,析构函数是自动调用的,如果显示调用是不会析构对象的。
    ……
    14:       a->bbb = 345;
    0040105B   mov         ecx,dword ptr [ebp-4]
    0040105E   mov         dword ptr [ecx],159h
    15:       a->~A();
    16:       a->fun();
    00401064   mov         ecx,dword ptr [ebp-4]
    00401067   call        @ILT+15(A::fun) (00401014)
    ……

    由以上可知,一个类只能有一个析构函数,析构函数没有返回值没有参数,只能由系统调用时才析构对象。

    展开全文
  • C++中有一个很重要的法则:使用构造函数创建对象的顺序与使用析构函数释放对象的顺序相反。对于一些C++的初学者来说,这是一条有点费解的法则,那么该怎么理解和清晰的表现出来呢?下面我们通过程序来体现一下: #...

           在C++中有一个很重要的法则:使用构造函数创建对象的顺序与使用析构函数释放对象的顺序相反。对于一些C++的初学者来说,这是一条有点费解的法则,那么该怎么理解和清晰的表现出来呢?下面我们通过程序来体现一下:

    #include<iostream>
    using namespace std;
    
    //创建一个汽车类
    class Car
    {
    public:
            //构造函数
    	Car(short, int);
            //析构函数
    	~Car();
    	void move();
    private:
    	short speed;
    	int num;
    };
    
    Car::Car(short s, int n)
    {
    	speed = s;
    	num = n;
    	cout << "创建第" << num << "辆车,速度是" << speed << " 米/秒" << endl;
    }
    
    Car::~Car()
    {
    	cout << "销毁掉第 " << num << "辆车" << endl;
    }
    
    void Car::move()
    {
    	cout << "第 " << num << "辆车速度是" << speed << endl;
    }
    
    //主函数
    void main()
    {
            //先创建第car1对象,再创建car2对象
    	Car car1(10, 1), car2(20, 2);
    	car1.move();
    	car2.move();
    }

           编译执行的结果如下(编译环境为Visual Studio 2013):


           分析输出结果,我们可以看到,在主函数中是首先创建了car1类,后创建了car2类,所以在执行构造函数的顺序上,是先执行car1对象的构造函数,后执行car2对象的构造函数。而在主函数执行结束,要调用析构函数的时候,根据开始说的法则,则会先执行car2类的析构函数,后执行car1类的析构函数。这就是“使用构造函数创建对象的顺序与使用析构函数释放对象的顺序相反”这条法则的一个很好的体现

           那么我们可以举一反三,如果想先执行car1类的析构函数,后执行car2类的析构函数,那么上述程序该如何修改呢?很简单,依据上述法则,我们只需要修改为先创建car2类,后创建car1类,就可以了。修改后的程序如下:

    #include<iostream>
    using namespace std;
    
    class Car
    {
    public:
    	Car(short, int);
    	~Car();
    	void move();
    private:
    	short speed;
    	int num;
    };
    
    Car::Car(short s, int n)
    {
    	speed = s;
    	num = n;
    	cout << "创建第" << num << "辆车,速度是" << speed << " 米/秒" << endl;
    }
    
    Car::~Car()
    {
    	cout << "销毁掉第 " << num << "辆车" << endl;
    }
    
    void Car::move()
    {
    	cout << "第 " << num << "辆车速度是" << speed << endl;
    }
    
    void main()
    {
            //这次先创建car2类,后创建car1类
    	Car car2(20, 2), car1(10, 1);
    	car1.move();
    	car2.move();
    }
           编译执行的结果如下:

           这次我们看到,由于是先创建了car2类,后创建了car1类,所以先执行了car2类的构造函数,后执行car1类的构造函数;而在最后,会先执行car1类的析构函数,后执行car2类的西沟函数。

           当然。我们还可以再往深了想一想,上面这两个例子都是基于同一个类来创建两个对象的,那么如果是两个不同的类创建的对象呢?是否依然符合这条法则呢?我们再修改程序来验证一下:

    #include<iostream>
    using namespace std;
    
    //创建一个汽车类
    class Car
    {
    public:
    	Car(short, int);
    	~Car();
    	void move();
    private:
    	short speed;
    	int num;
    };
    
    //创建一个司机类
    class Driver
    {
    public:
    	Driver(short);
    	~Driver();
    	void drive();
    private:
    	short years;
    };
    
    Car::Car(short s, int n)
    {
    	speed = s;
    	num = n;
    	cout << "创建第" << num << "辆车,速度是" << speed << " 米/秒" << endl;
    }
    
    Car::~Car()
    {
    	cout << "销毁掉第 " << num << "辆车" << endl;
    }
    
    void Car::move()
    {
    	cout << "第 " << num << "辆车速度是" << speed << endl;
    }
    
    Driver::Driver(short y)
    {
    	cout << "我是一个" << y << "岁的司机" << endl;
    }
    
    Driver::~Driver()
    {
    	cout << "我要停车了" << endl;
    }
    
    void Driver::drive()
    {
    	cout << "我要开车了" << endl;
    }
    
    //主函数
    void main()
    {
            //先创建汽车类
    	Car car1(10, 1);
            //后创建司机类
    	Driver driver1(30);
    	driver1.drive();
    	car1.move();
    }
           编译执行的结果如下:

           通过输出结果,我们可以看到,先执行了Car1类的构造函数,后执行了Driver1类的构造函数,而在最后,则是先执行了Driver1类的析构函数,后执行了Car1类的析构函数,也就是说,不同的类依然是符合上述法则的

           上述例子较为简单,而在实际应用中,主函数中可能远比上述程序复杂的多,可能会执行更多的类操作,这样就需要我们去时刻注意一下这条法则,避免出现一些看起来很“莫名其妙”的错误。



    展开全文
  • 析构函数

    2021-01-17 17:48:57
    析构函数也是一个中跟构造函数类似的特殊功能的成员函数,作用与构造函数相反,是在对象的声明周期结束的时候会被自动调用.在C++中析构函数的名字跟类名相同,并在前面带上一个取反的符号~,表达的意思也跟构造...

    析构函数也是一个在类中跟构造函数类似的特殊功能的成员函数,作用与构造函数相反,是在对象的声明周期结束的时候会被自动调用.在C++中析构函数的名字跟类名相同,并在前面带上一个取反的符号~,表达的意思也跟构造函数的过程相反.

    默认情况下,如果类没有定义自己的析构函数,编译器会自动为该类生成一个默认的析构函数,只不过函数体是空的,也就是什么都没做.所有,如果需要在对象被删除的时候做一些操作的话,就得自己定义析构函数.


    以下几种情况会自动调用析构函数:
    ①如果一个函数中定义了一个局部变量的对象,那么当这个函数执行结束时也就是该变量对象生命周期结束的时候,所以析构函数会被自动调用.
    ②全局变量或者static类型的变量,他们的生命周期一般是在程序退出的时候,该对象的析构函数才会被调用.
    ③如果是用new操作符动态的创建了一个对象,只有当用delete进行释放该对象的时候,析构函数才会被调用.


    析构函数的作用:
    那构造函数来说,构造函数是新建对象吗?不是,而是在对象被创建出来后自动被调用的,用来初始化相关信息的函数.同理:析构函数也不是用来删除对象的,而是当对象被删除的时候自动被调用的,用来做一些对象被删除之前的清理工作,只有对象的生命周期结束,那么程序就自动执行析构函数来完成这个工作.


    析构函数的特点:
    析构函数不返回任何值,没有函数类型,也没有任何函数的参数.析构函数不能被重载,所以,一个类中可以有多个构造函数,但只有一个析构函数.


    析构函数使用示例:

    CStudent::~CStudnet()
    {
    	cout<<"~CStudent() callec."<<endl;
    }
    

    //本文来源于VC驿站,仅作为个人学习记录

    展开全文
  • C++ 析构函数

    万次阅读 多人点赞 2016-09-21 00:02:15
    析构函数如果我们不写的话,C++ 会帮我们自动的合成一个,就是说:C++ 会自动的帮我们写一个析构函数。很时候,自动生成的析构函数可以很好的工作,但是一些重要的事迹,就必须我们自己去写析构函数。 析构函数...

    C++ 析构函数

    我使用的继承开发环境: Visual Studio 2010


    设计一个类时,如何写析构函数?
    析构函数如果我们不写的话,C++ 会帮我们自动的合成一个,就是说:C++ 会自动的帮我们写一个析构函数。很多时候,自动生成的析构函数可以很好的工作,但是一些重要的事迹,就必须我们自己去写析构函数。
    析构函数和构造函数是一对。构造函数用于创建对象,而析构函数是用来撤销对象。简单的说:一个对象出生的时候,使用构造函数,死掉的时候,使用析构函数。

    下面我们来做一个例子,看看:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class NoName{
    public:
        NoName():pstring(new std::string), i(0), d(0){}
    private:
        std::string * pstring;
        int i;
        double d;
    };
    
    int main(){
    
        return 0;
    }

    像上面这个 NoName 类这样的设计,类里面有一个成员变量是指针(std::string *pstring) ,那么在构造函数里我们使用 new 创建了对象,并使用 pstring 来操作这个对象。那么在这个情况下,我们就必须设计一个析构函数。

    析构函数是这样编写的:(可以在类的里面声明,定义写在类的外面,)

    class NoName{
    public:
        NoName():pstring(new std::string)
            , i(0), d(0){
            cout << "构造函数被调用了!" << endl;
        }
        ~NoName();
    NoName::~NoName(){
        cout << "析构函数被调用了!" << endl;
    }

    析构函数是这样写的: ~NoName() ,它与构造函数唯一的区别就是,前面都加了一个 ~ 符号。 析构函数都是没有参数的,也就是说:析构函数永远只能写一个。
    按照 C++ 的要求,只要有 new 就要有相应的 delete 。这个 new 是在构造函数里 new 的,就是出生的时候。所以在死掉的时候,就是调用析构函数时,我们必须对指针进行 delete 操作。

    我们来在main() 函数中创建一个 NoName 实例对象来 测试一下:

    int main(){
        NoName a;
    
        return 0;
    }

    并且在 main() 函数的 } 这一行添加一个断点,如图所示:

    这里写图片描述

    运行输出:

    构造函数被调用了!
    析构函数被调用了!

    在定义 a 对象的时候,调用了 NoName 类的构造函数,在main() 函数执行完的时候,就是执行完 return 0; 这句话后,main() 函数的执行域结束,所以就要杀掉 a 对象,所以这个时候会调用 NoName 类的析构函数。

    那么,如果我们在 main() 函数中使用 new 关键字来创建一个 NoName 类的实例化对象,会出现什么样的运行效果呢?
    main() 函数中的代码如下:

    int main(){
        NoName a;
        NoName *p = new NoName;
    
        return 0;
    }

    运行输出:

    构造函数被调用了!
    构造函数被调用了!
    析构函数被调用了!

    这里使用 new 创建的对象,就必须要使用 delete 来释放它。 牢牢的记住:newdelete 是一对。正确的代码是下面这个样子的:

    int main(){
        NoName a;
        NoName *p = new NoName;
    
        delete p;
        return 0;
    }

    运行输出:

    构造函数被调用了!
    构造函数被调用了!
    析构函数被调用了!
    析构函数被调用了!

    构造函数 和 析构函数 各有各的用途,在构造函数中,我们来获取资源;在析构函数中,我们来释放资源。释放了之后,这些资源就会被回收,可以被重新利用。
    比如说,我们在构造函数里打开文件,在析构函数里关闭打开的文件。这是一个比较好的做法。
    在构造函数里,我们去连接数据库的连接,在析构函数里关闭数据库的连接。
    在构造函数里动态的分配内存,那么在析构函数里把动态分配的内存回收。

    构造函数 和 析构函数 之间的操作是向对应的。
    如果我们不写析构函数,C++ 会帮我们写一个析构函数。C++帮我们写的这个析构函数只能做一些很简单的工作,它不会帮助我们去打开文件、连接数据库、分配内存这些操作,相应的回收,它也不会给我们写。所以需要我们自己手动的写。(如果要做这些操作,我们必须自己写。)

    如果我们自己写了析构函数,记住三个原则:
    如果你写了析构函数,就必须同时写赋值构造函数 和 赋值操作符。你不可能只写一个。

    赋值构造函数:

    在赋值的时候,不是讲指针赋值过来,而是将指针对应指向的字符串赋值过来,这是最关键的一步。

    因为我们写了析构函数,就必须要将赋值构造函数写上:

    class NoName{
    public:
        NoName():pstring(new std::string)
            , i(0), d(0){
            cout << "构造函数被调用了!" << endl;
        }
        NoName(const NoName & other);
        ~NoName();
    NoName::NoName(const NoName & other){
        pstring = new std::string;
        *pstring = *(other.pstring);
        i = other.i;
        d = other.d;
    }

    除了要写 赋值构造函数,还要写赋值操作符。

    class NoName{
    public:
        NoName():pstring(new std::string)
            , i(0), d(0){
            cout << "构造函数被调用了!" << endl;
        }
        NoName(const NoName & other);
        ~NoName();
    
        NoName& operator =(const NoName &rhs);
    NoName& NoName::operator=(const NoName &rhs){
        pstring = new std::string;
        *pstring = *(other.pstring);
        i = other.i;
        d = other.d;
        return *this;
    }

    只要你写了析构函数,就必须要写 赋值构造函数 和 赋值运算符,这就是著名的 三法则 (rule of three



    总结:

    在设计一个类的时候,如果我们一个构造函数都没有写,那么 C++ 会帮我们写一个构造函数。只要我们写了一个构造函数,那么 C++ 就不会再帮我们写构造函数了。

    构造函数可以重载,可以写很多个,析构函数不能重载,只能写一个。如果我们没有写析构函数,C++会自动帮我们写一个析构函数。那么在工作的时候,我们写的析构函数会被调用,调用完成之后,C++会执行它自动生成的析构函数。

    如果我们写的类是一个没有那么复杂的类,我们可以不需要写析构函数。如果一个类只要有这些情况:打开文件、动态分配内存、连接数据库。简单的说:就是只要构造函数里面有了 new 这个关键词,我们就需要自己手动编写析构函数。

    那么如果我们写了析构函数,就必须要注意三法则:同时编写:析构函数、赋值构造函数、赋值运算符。

    完整的代码:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class NoName{
    public:
        NoName():pstring(new std::string)
            , i(0), d(0){
            cout << "构造函数被调用了!" << endl;
        }
        NoName(const NoName & other);
        ~NoName();
    
        NoName& operator =(const NoName &rhs);
    private:
        std::string * pstring;
        int i;
        double d;
    };
    
    NoName::~NoName(){
        cout << "析构函数被调用了!" << endl;
    }
    
    NoName::NoName(const NoName & other){
        pstring = new std::string;
        *pstring = *(other.pstring);
        i = other.i;
        d = other.d;
    }
    
    NoName& NoName::operator=(const NoName &rhs){
        pstring = new std::string;
        *pstring = *(rhs.pstring);
        i = rhs.i;
        d = rhs.d;
        return *this;
    }
    
    int main(){
        NoName a;
        NoName *p = new NoName;
    
        delete p;
        return 0;
    }
    展开全文
  • C++虚析构函数、纯虚析构函数

    千次阅读 2016-03-01 18:18:44
    因为在C++中,当一个派生对象通过使用一个基类指针删除,而这个基类有一个非虚的析构函数,则结果是未定义的。运行时比较代表性的后果是对象的派生部分不会被销毁。然而,基类部分很可能已被销毁,这就导致了...
  • C#析构函数

    千次阅读 2017-01-11 19:04:36
    一个类只能个析构函数。 无法继承或重载析构函数。 无法调用析构函数。它们是被自动调用的。 析构函数既没有修饰符,也没有参数。 例如,下面是 Car 的析构函数的声明: class Car {
  • 析构函数的作用及合成析构函数

    千次阅读 2013-11-30 02:05:33
    析构函数 用于释放在构造函数或在对象生命期内获取的资源。 如果需要析构函数,那么也需要复制操作符和复制构造函数。...编译器总是为我们合成一个析构函数,合成析构函数按对象创建时的逆序撤销每个非static成员,
  • C++析构函数

    2019-09-23 08:45:21
    C++析构函数 一、认识析构函数 析构函数也是一种特殊... 一个类只能个析构函数,如果没有显式的定义,系统会生成一个缺省的析构函数(合成析构函数)。 因为无参数无返回值析构函数不能重载。每一次构...
  • C++虚析构函数及纯虚析构函数

    千次阅读 2016-09-14 23:40:49
    C++中析构函数可以为纯虚吗? 众所周知,在实现多态的过程中,一般将基类的析构函数设为virtual,以便在delete的时候能够多态的链式调用。那么析构函数是否可以设为纯虚呢? class CBase { public: CBase() { ...
  • 一个包含着构造函数虚析构函数类大小为多少? #include class SizeOfClass{ public: SizeOfClass(){ } virtual ~SizeOfClass(){ } }; int main() { using std::cout; using std::endl; SizeOfClass ...
  • C++的构造函数与析构函数

    千次阅读 2016-06-29 22:11:09
    C++中每个类其构造与析构函数,它们负责对象的创建和对象的清理和回收,即使我们不写这两,编译器也会默认为我们提供这些构造函数。下面仍然是通过反汇编的方式来说明C++中构造和析构函数是如何工作的。编译器...
  • 析构函数与合成析构函数

    千次阅读 2012-02-28 16:37:33
    今天看《c++ primer》的时候,突然看到合成析构函数这个名词,对析构函数了解的多点,对合成析构函数则了解的不析构函数特点: 1.整个只有一个,即不能重载; 2.没有形参; 3.没有返回值; 4.不能被继承...
  • 构造函数与析构函数

    2016-02-16 14:46:56
    构造函数一个同名的方法,可以没有参数,有一个参数或多个参数,但是构造函数没有返回值。如果构造函数没有参数,该函数被称为的默认构造函数。 (1) 一个类可以包含多个构造函数,各个构造函数之间通过...
  • C++中析构函数为虚函数

    千次阅读 多人点赞 2019-04-12 23:13:17
    (1)析构函数定义为虚函数时:基类指针可以指向派生的对象(态性),如果删除该指针delete []p;就会调用该指针指向的派生类析构函数,而派生析构函数又自动调用基类的析构函数,这样整个派生的对象完全...
  • C++虚析构函数与纯虚析构函数

    千次阅读 2013-07-28 20:24:07
    因为在C++中,当一个派生对象通过使用一个基类指针删除,而这个基类有一个非虚的析构函数,则结果是未定义的。运行时比较代表性的后果是对象的派生部分不会被销毁。然而,基类部分很可能已被销毁,这就导致了...
  • 析构函数遇到线程
  • 默认构造函数指不带参数或者所有参数都缺省值的构造函数!...每个只有一个析构函数一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数)。对于任意一个类A,如果不编写上述
  • C++中析构函数可以为纯虚吗?  众所周知,在实现多态的过程中,一般将基类的析构函数设为virtual,以便在delete的时候能够多态的链式调用。那么析构函数是否可以设为纯虚呢? class CBase {  public:  CBase...
  • 1. 析构函数和虚析构函数 如果基类的析构函数是虚的,那么它的派生析构函数都是虚的 这将导致:当派生析构的时候,它的所有的基类的析构函数都将得到调用 否则,只调用派生析构函数(这可能导致基类的...
  • 派生的构造函数与析构函数: 派生不能继承基类的构造函数和析构函数,必须自己定义。由于派生与基类的特殊关系,在设计派生的构造函数时,不仅要考虑派生新增数据成员的初始化, 也要考虑基类数据成员的...
  • 派生的构造函数与析构函数的调用顺序 前面已经提到,构造函数和析构函数的调用顺序是先构造的后析构,后构造的先析构。 那么基类和派生中的构造函数和析构函数的调用顺序是否也是如此呢? 构造函数的调用...
  •  每个只有一个析构函数一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数)。对于任意一个类A,如果不想编写上述函数,C++编译器将自动为A产生四个缺省的函数,如  A(void)...
  • 每个只有一个析构函数一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数)。对于任意一个类A,如果不想编写上述函数,C++编译器将自动为A产生四个缺省的函数
  • C++函数之的构造函数析构函数

    千次阅读 2015-02-25 10:01:59
    对于对象成员的初始化我们始终是...关于C++成员的初始化,专门的构造函数来进行自动操作而无需要手工调用,在正式讲解之前先看看c++对构造函数一个基本定义:  1,C++规定,每个必须默认的构造函数,没
  • 一个包含着构造函数析构函数(非虚)大小为多少? #include class SizeOfClass{ public: SizeOfClass(){ } ~SizeOfClass(){ } }; int main() { using std::cout; using std::endl; SizeOfClass instance;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 109,199
精华内容 43,679
关键字:

一个类有多个析构函数