[Reprint]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、  

  •   
  • using namespace std;  
  •   
  • class Box  
  • {  
  • private:  
  •     double length;  
  • public:  
  •     Box(double lv=1.0):length(lv)//构造函数都没有返回值  
  •     {  
  •         cout << "constructor called" << endl;  
  •     }  
  •   
  •     ~Box()  
  •     {  
  •         cout << "destructor called" << endl;  
  •     }  
  •   
  •     void showit()  
  •     {  
  •         cout << this->length << endl;  
  •     }  
  • };  
  •   
  • void display(Box box)//关键注意这个地方。。。。。。。。。。。。。。。。。。。。。。。。。  
  • {  
  •     box.showit();  
  • }  
  • int main()  
  • {  
  •         Box box;  
  •         display(box);  
  • }  



运行结果

如果将上面的display代码改为

  1. void display(Box &box)//改为调用的是引用  
  2. {  
  3.     box.showit();  
  4. }  

运行结果



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

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


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


转载于:https://www.cnblogs.com/hualiu0/p/5635871.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
reprint 使用说明 本人长期使用delphi做数据库的开发,报表控件使用Quickrpt,在打印上经常遇到一些问题,于是自己经常编写一部分打印的程序,经过总结开发了这个控件。 本控件可打印 datasource,dbgrid,stringgrid. 一 、控件属性: 1、colstitle 设置报表的列标题属性 (1)alignment 列标题对齐方式。 (2)font 列标题字体 (3)print 设置是否打印列标题 (4)rowspace 列标题行的高度 2、datasource 选择要打印的datasource 3、dbgrid 选择要打印的dbgrid 4、stringgrid 选择要打印的stringgrid 5、detail 设置要打印的明细数据属性 (1)arrange 设置明细字段排列方向 Horizontal 横向打印(默认的一般打印) Vertical 竖向打印(字段竖向排列适合打印字段内容较长的报表如“会议纪录”) (2)aotureturn 打印明细字段时,如果字段超过列的宽度是否允许自动换行 (3)colsline 设置竖线属性引用tpen类 (4)footer 设置明细尾 (5)frame 设置明细边框属性引用tpen类 (6)head 设置明细头同footer (7)rowsline 设置横线属性引用tpen类 (8)rowspace 设置明细行的高度 (9)top 明细与标题的距离 6、page 设置纸张的上下左右边距 7、pagefooter 设置页脚同明细尾 8、pageheader 设置页眉同页脚 9、printobject 选择要打印的对象 (datasource 、dbgrid、 stringgrid ) 10、title 设置标题类页眉、页脚 二 、控件方法: (1) preview 预览 (2) print 打印 (3) SaveToFile() 保存为报表文件 (4) SaveToStream() 保存为流(然后就可把整个报表存到数据库了很方便哦! ~_~) (5) PrintFile() 打印报表文件 (6) PrintStream() 打印流(流的数据库存取就不用多说了吧) (7) PreviewFile() 预览文件 (8) PreviewStream() 预览流 (9) OptionToStream() 报表的属性保存为流 (10) OptionFromStream() 从流中得到报表属性 三、 控件事件: AfterPrint 打印后 BeforePrint 打印前 (本来很多事件,但没有预览,后来加上预览以及一些方法后实现很困难就去掉了!) 四、注意事项 (1) text 属性,输入“¦;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#¦;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;”打印页码值,如果想打印页码可输入“第¦;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#¦;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;页” 输入“¦;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;RecordCount¦;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;”打印 记录数 (2) 不同的打印机,打印和预览效果可能有一点点不同(保证数据打印完全正确一致)。本人用一台针式和一台激光打印机做测试,开始差别较大后经过调试基本一致,不知其他打印机如何。 就这些个吧基本满足了我的软件开发需要,解决了很多问题,关键是做报表省了很大力气,当然了很复杂的报表还是要其它报表控件来解决。如果有其他问题或好的建议可与我联系。 程序设计:吴进昊 E-mail :jinhaowu@hotmail.com qq :54254770 2003.01.03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值