24H免费课程咨询  TEL:13401595960   QQ:1870218756  微信:13401595960(李老师)

东方博宜

常州软件开发培训班
网站首页 > 软件开发资讯 > C/C++

浅析C++构造方法和析构方法调用时机的问题?

2017-06-01 19:04:23 东方博宜 阅读

在C++中构造方法和析构方法什么时候会调用?什么时候真正生成对象?什么时候会自动调用析构方法销毁对象?请看本文详细讲解!

  1. #include <iostream>  

  2.   

  3. using namespace std;  

  4.   

  5. class Box  

  6. {  

  7. private:  

  8.     double length;  

  9. public:  

  10.     Box(double lv=1.0):length(lv)//构造函数都没有返回值  

  11.     {  

  12.         cout << "constructor called" << endl;  

  13.     }  

  14.   

  15.     ~Box()//重写的析构函数(重写是对继承类对基类的重新构造,这里表述不对)  

  16.     {  

  17.         cout << "destructor called" << endl;  

  18.     }  

  19. };//万恶的分号,我老是忘掉  


1、首先直接声明(定义)看下

//很多朋友指出我这里用声明不合适,在11楼作了一定解释,具体不在这里赘述,这里改为“定义”,谢谢大家的指正,但我也保留我自己的意见,所以没有把“声明”去掉



  1. int main()  

  2. {  

  3.     Box box(2.3);  

  4. }  



这里看到一点Java与c++的不同点,c++在声明的时候就创建了对象,java声明只是创建一个引用,并不会分配内存。言归正传,说明声明以后就调用了构造函数,然后退出的时候调用析构函数。


2、声明指针


  1. int main()  

  2. {  

  3.     Box *box;  

  4. }  




可以看到,声明指针并不会调用构造函数,也不会分配内存空间。


3、用new创建


  1. int main()  

  2. {  

  3.     Box *box=new Box(2.3);  

  4. }  




仅仅是调用构造函数创建了对象,分配了内存空间。但是没有调用析构函数,因为box指定的对象的内存是由new来创建分配的,编译器不能够自动调用析构函数将其删除。所以需要调用delete才可以。


4、用new创建对象,并delete掉


  1. int main()  

  2. {  

  3.     Box *box=new Box();  

  4.     delete box;  

  5. }  




这次调用了析构函数。可以看出,此时的析构函数不是编译器自己调用的,是由我们的程序来主动调用的,所以以后需要注意。new了的需要手动释放内存空间


5、什么时候需要重写析构函数?



  1. class Message()  

  2. {  

  3. private:  

  4.     char *message;  

  5. public:  

  6.     Message(const char* text="default message")  

  7.     {  

  8.         message = new char[strlen(text)+1];  

  9.         strcpy(message, text);  

  10.     }  

  11.   

  12.     void showit()  

  13.     {  

  14.         cout << "message: " << message << endl;  

  15.     }  

  16.   

  17.     ~Message()  

  18. };  

  19.   

  20. Message::~Message()  

  21. {  

  22.     cout << "destructor called" << endl;  

  23.     delete [] message;  

  24. }  


从例子可以看到,当你的构造函数中调用了new来创建对象的内存分配空间,则需要专门调用delete来释放内存,所以此时需要覆写析构函数,来专门的释放此内存空间


6、对象的形参传值问题:(话外题,仅作记录用)

先看代码及运行结果

  1. #include <iostream>  

  2.   

  3. using namespace std;  

  4.   

  5. class Box  

  6. {  

  7. private:  

  8.     double length;  

  9. public:  

  10.     Box(double lv=1.0):length(lv)//构造函数都没有返回值  

  11.     {  

  12.         cout << "constructor called" << endl;  

  13.     }  

  14.   

  15.     ~Box()  

  16.     {  

  17.         cout << "destructor called" << endl;  

  18.     }  

  19.   

  20.     void showit()  

  21.     {  

  22.         cout << this->length << endl;  

  23.     }  

  24. };  

  25.   

  26. void display(Box box)//关键注意这个地方。。。。。。。。。。。。。。。。。。。。。。。。。  

  27. {  

  28.     box.showit();  

  29. }  

  30. int main()  

  31. {  

  32.         Box box;  

  33.         display(box);  

  34. }  




运行结果

如果将上面的display代码改为



  1. void display(Box &box)//改为调用的是引用  

  2. {  

  3.     box.showit();  

  4. }  

运行结果




可以明显的看到不加引用的时候会出现两个析构函数的调用。为什么呢?

直接传参,是形参传递,所以会另外创建一个对象来复制main函数里的对象box,所以在display调用完成时刻要调用析构函数来释放这个函数创建的形参对象的内存空间。但是如果是传递的引用,就只有一个参数对象了,所以只调用一个。


如果是平时的基本类型,你应该了解,直接把main里的box的值复制给形参box就是了,但是到了对象这里就有点复杂,如果是里面就是单纯的像上面的例子一样double类型等,其自带有复制函数就可以将各个成员值复制到形参对象里,但是如果里面有引用,比如char *pp = new char[100],那么复制的只是地址,两个对象公用一个地址,有可能就会造成错误。所以以后需要注意这一点,调用对象需要用引用哦。。。。。(要不你自己另写一个复制函数。)




Powered by 东方博宜教育咨询江苏有限公司  ©2008-2017 www.czos.cn