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

  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. python 时间及日期函数

    本人最近新学python ,用到关于时间和日期的函数,经过一番研究,从网上查找资料,经过测试,总结了一下相关的方法. import timeimport datetime '''时间转化为时间戳: 2 ...

  2. C#基础|初探反射

    什么是反射 我们编写的C#代码都可以编译成exe文件或dll文件.暂时先把他们叫做程序集吧,程序集中包含了很多信息.你写了一个类,类中会有字段,有属性,有方法,编译是会把这些信息保存在程序集中,暂时把 ...

  3. python常用绘图软件包记录

    在没有使用python之前,觉得matlab的绘图功能还算可以~但现在发现python的绘图包真的好强大,绘制出的图像非常专业漂亮,但具体使用还有待学习,这里记录学习过程中遇到的python绘图包,以 ...

  4. 关于PIL库的一些概念

    关于PIL库的一些概念 pil能处理的图片类型pil可以处理光栅图片(像素数据组成的的块). 通道一个图片可以包含一到多个数据通道,如果这些通道具有相同的维数和深度,Pil允许将这些通道进行叠加 模式 ...

  5. "Money, Money, Money"

    acdream1408:http://115.28.76.232/problem?pid=1408 题意:给你一个x,让你构造a,b,是的na+bm可以组成大于x的所有的数.a>1,b>1 ...

  6. cat命令常用的13个技巧

    在Linux系统中,大多数配置文件.日志文件,甚至shell脚本都使用文本文件格式,因此,Linux系统存在着多种文本编辑器,但当你仅仅想要查看一下这些文件的内容时,可使用一个简单的命令-cat. c ...

  7. Android ListView(Selector 背景图片)

    listview0.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmln ...

  8. easyui源码翻译1.32--Tabs(选项卡)

    前言 使用$.fn.tabs.defaults重写默认值对象.下载该插件翻译源码 选项卡显示一批面板.但在同一个时间只会显示一个面板.每个选项卡面板都有头标题和一些小的按钮工具菜单,包括关闭按钮和其他 ...

  9. Oracle Kill Session – FRM-40501

    FRM-40501: ORACLE error: unable to reserve record for update or delete frm-40501:oracle 错误:无法保留用于更新或 ...

  10. open MMT.distributions = null on transaction type: WIP Lot Split

    open MMT.distributions = null on transaction type:  WIP Lot Split       打开物料事务处理界面,发现事务处理类型为:WIP Lot ...