今天看书忽然对这个地方有点模糊,尤其是析构函数在调用默认的析构函数和用户自己覆写的析构函数的时候有点意识模糊呢。写段代码总结下

  1. #include <iostream>
  2. using namespace std;
  3. class Box
  4. {
  5. private:
  6. double length;
  7. public:
  8. Box(double lv=1.0):length(lv)//构造函数都没有返回值
  9. {
  10. cout << "constructor called" << endl;
  11. }
  12. ~Box()//重写的析构函数(重写是对继承类对基类的重新构造,这里表述不对)
  13. {
  14. cout << "destructor called" << endl;
  15. }
  16. };//万恶的分号,我老是忘掉

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. void showit()
  12. {
  13. cout << "message: " << message << endl;
  14. }
  15. ~Message()
  16. };
  17. Message::~Message()
  18. {
  19. cout << "destructor called" << endl;
  20. delete [] message;
  21. }

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

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

先看代码及运行结果

  1. #include <iostream>
  2. using namespace std;
  3. class Box
  4. {
  5. private:
  6. double length;
  7. public:
  8. Box(double lv=1.0):length(lv)//构造函数都没有返回值
  9. {
  10. cout << "constructor called" << endl;
  11. }
  12. ~Box()
  13. {
  14. cout << "destructor called" << endl;
  15. }
  16. void showit()
  17. {
  18. cout << this->length << endl;
  19. }
  20. };
  21. void display(Box box)//关键注意这个地方。。。。。。。。。。。。。。。。。。。。。。。。。
  22. {
  23. box.showit();
  24. }
  25. int main()
  26. {
  27. Box box;
  28. display(box);
  29. }

运行结果

如果将上面的display代码改为

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

运行结果

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

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

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

C++中构造函数和析构函数调用的时机的更多相关文章

  1. C++类的继承中构造函数和析构函数调用顺序例子

    /*当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达派生类次数最多的派生次数最多的类的构造函数为止.简而言之,对象是由“底层向上”开始构造的.因为,构造函数 ...

  2. C++构造函数和析构函数调用虚函数时都不会使用动态联编

    先看一个例子: #include <iostream> using namespace std; class A{ public: A() { show(); } virtual void ...

  3. C++单继承的构造函数和析构函数调用的顺序

    1.继承构造函数调用顺序以及销毁的过程 先调用父类的构造函数,在调用子类的构造函数,析构函数调用相反.

  4. [第二章]c++学习笔记5(构造函数和析构函数调用时机)

    示例函数 注:输出并不一定从main函数开始,如全局对象的初始化在main函数前执行,如构造函数中存在输出,则从构造函数的输出开始 此处6被类型转换构造函数的存在转换为临时对象赋值,而在这个过程结束后 ...

  5. C++ 构造函数或析构函数调用虚函数

    构造函数和析构函数中的虚函数 在执行基类构造函数时,对象的派生类部分是未初始化的.实际上,此时对象还不是一个派生类对象. 为 了适应这种不完整,编译器将对象的类型视为在构造或析构期间发生了变化.在基类 ...

  6. 12.C++-构造函数与析构函数调用顺序,const成员函数,const对象

    单个对象创建时,构造函数的调用顺序 1.首先判断该对象的类是否拥有父类,若有则先调用父类的构造函数 2.判断该对象的成员是否是其它类的成员,若是则调用成员变量的构造函数(调用顺序和声明顺序相同) 3. ...

  7. C++C++中构造函数与析构函数的调用顺序

    http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2 ...

  8. c++深/浅拷贝 && 构造函数析构函数调用顺序练习题

    1.深/浅拷贝 编译器为我们提供的合成拷贝构造函数以及合成的拷贝赋值运算符都是浅拷贝.浅拷贝只是做简单的复制,如果在类的构造函数中new出了内存,浅拷贝只会简单的复制一份指向该内存的指针,而不会再开辟 ...

  9. C++中构造函数和析构函数的调用顺序

    一般而言,析构函数调用的顺序和构造函数调用顺序相反,但是,对象的存储类别可以改变调用析构函数的顺序.举例说明: CreateAndDestroy类的定义 CreateAndDestroy类的成员函数的 ...

随机推荐

  1. DB2实用命令记录

    quiesce tablespace quiesce tablespaces for table <table_name> share; Monitor Switches details ...

  2. 用 BPL 封装数据连接

    BPL 代码: uDM.pas unit uDM; interface uses SysUtils, Classes, uIntf, DB, ABSMain; type TDM = class(TDa ...

  3. platform平台设备驱动简化示例代码

    driver.c: #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h& ...

  4. python编程语言 函数的形参

    python编程语言 函数的形参的讲解: 我在交互模式中写了个函数: def adder(**args): sum=0 for x in args.keys(): sum+=args[x] retur ...

  5. Python设计模式——模版方法模式

    1.模版方法模式 做题的列子: 需求:有两个学生,要回答问题,写出自己的答案 #encoding=utf-8 __author__ = 'kevinlu1010@qq.com' class Stude ...

  6. python 程序列表

    用 python  通过读取注册表来获取机器安装的程序列表,包括,软件名称,版本号,安装日期等 # -*- coding: UTF8 -*-import _winregimport osimport ...

  7. 数据结构---顺序表(C++)

    顺序表 是用一段地址连续的存储单元依次存储线性表的数据元素. 通常用一维数组来实现 基本操作: 初始化 销毁 求长 按位查找 按值查找 插入元素 删除位置i的元素 判空操作 遍历操作 示例代码: // ...

  8. SpringMVC的controller方法中注解方式传List参数使用@RequestBody

    在SpringMVC控制器方法中使用注解方式传List类型的参数时,要使用@RequestBody注解而不是@RequestParam注解: //创建文件夹 @RequestMapping(value ...

  9. 取得inputStream的长度

    1.网络下载文件 URL url = new URL(strUrl); HttpURLConnection httpconn = (HttpURLConnection)url.openConnecti ...

  10. php PDO连接mysql以及字符乱码处理

    <?php //mysql 的 PDO $dsn = "mysql:dbname=cqkx;host:localhost"; $username = "root&q ...