C++编程入门系列之十四(类与对象:构造函数和析构函数)


鸡啄米上一节中给大家讲解了类的声明、成员的访问控制和对象,今天鸡啄米给大家讲C++编程入门时同样必须掌握的构造函数和析构函数。从上一讲开始已经涉及到了很多面向对象设计的细节,大家慢慢跟着学习思考吧,实际上跟我们现实中的很多做事的思想是一致的,这也正是面向对象语言的特点,它是以现实中的事物和围绕事物处理问题的思路为基础的。

某个类的对象之间都有哪些不同呢?首先是对象名不同,其次就是对象的数据成员的值不同。我们在声明一个对象时,也可以同时给它的数据成员赋初值,称为对象的初始化。

1.构造函数

我们在声明一个变量时,如果对它进行了初始化,那么在为此变量分配内存空间时还会向内存单元中写入变量的初始化。声明对象有相似的过程,程序执行时遇到对象声明语句时会向操作系统申请一定的内存空间来存放这个对象,但是它能像一般变量那样初始化时写入指定的初始值吗?类的对象太复杂了,要实现这一点不太容易,这就需要构造函数来实现。

构造函数的作用就是在对象被创建时利用特定的初始值构造对象,把对象置于某一个初始状态,它在对象被创建的时候由系统自动调用,我们只需要使用默认的构造函数或者自己定义构造函数,而不用管怎么调用的。

构造函数也是类的成员函数,除了有成员函数的所有特征外,还有一些不同之处:构造函数的函数名跟类名一样,而且没有返回值。构造函数一般被声明为公有函数,除非我们不允许某个类生成对象则将它声明为private或protected属性。编译器碰到对象声明语句时,会自动生成对构造函数的调用语句,所以我们常说构造函数是在对象声明时由系统自动调用的。

上一讲那个时钟例子中,鸡啄米没有定义Clock类的构造函数,编译器编译时会自动生成一个默认形式的构造函数,这个构造函数不做任何事,那么为什么还要生成它呢?因为C++在对象建立时都会调用构造函数,所以如果没有自己定义构造函数,那么即使是什么都不做的构造函数也是要有的。鸡啄米现在在Clock类中加入自己定义的构造函数:

  class Clock{public:Clock(int NewH, int NewM, int NewS);              //构造函数void SetTime(int NewH, int NewM, int NewS);void ShowTime();private:int Hour, Minute, Second;};

构造函数的实现:

  Clock::Clock(int NewH, int NewM, int NewS){Hour=NewH;Minute=NewM;Second=NewS;}

建立对象时构造函数的作用:

    int main(){Clock c(0,0,0); //隐含调用构造函数,将初始值作为实参。c.ShowTime();return 0;}

main函数中,创建对象c时,其实隐含了构造函数的调用,将初始值0,0,0作为构造函数的实参传入。因为上面Clock类定义了构造函数,那么编译器就不会再为它生成默认构造函数了。这里的构造函数有三个形参,那么建立对象就必须给出初始值了。

因为构造函数也是一个成员函数,所以它可以直接访问类的所有数据成员,可以是内联函数,可以带有形参表,可以带默认的形参值,也可以重载,就是有若干个名字相同但形参个数或者类型不同的构造函数。

2.拷贝构造函数

我们可以将一个变量的值赋给另一个同类型的变量,那么可以将一个对象的内容拷贝给相同类的另一个对象吗?可以,我们可以将第一个对象的数据变量的值分别赋给另一个对象的数据变量,但是,如果数据变量数很多的话那将是很麻烦的,这时候我们就需要有拷贝构造函数。

拷贝构造函数是一种特殊的构造函数,因为它也是用来构造对象的。它具有构造函数的所有特性。拷贝构造函数的作用是用一个已经存在的对象去初始化另一个对象,这两个对象的类类型应该是一样的。定义拷贝构造函数的形式是:

   class 类名{ public :类名(形参);                    //构造函数类名(类名 &对象名);   //拷贝构造函数...};类名::类(类名 &对象名)    //拷贝构造函数的实现{   函数体    }

拷贝构造函数的形参是本类的对象的引用。

程序中如果没有定义拷贝构造函数系统会生成一个默认的拷贝构造函数,它会将作为初始值的对象的数据成员的值都拷贝到要初始化的对象中。下面鸡啄米给大家一个坐标点类的例子,X和Y数据成员分别为点的横坐标和纵坐标:

   class Point{public:Point(int xx=0,int yy=0)    {X=xx; Y=yy;}Point(Point &p);int GetX() {return X;}int GetY() {return Y;}private:int  X, Y;};

此类中声明了内联构造函数和拷贝构造函数。拷贝构造函数的实现如下:

  Point::Point(Point &p){X=p.X;Y=p.Y;cout<<"拷贝构造函数被调用"<<endl;}

拷贝构造函数在以下三种情况下会被调用:

a.当用类的一个对象去初始化该类的另一个对象时系统自动调用拷贝构造函数实现拷贝赋值。

   int main(){  Point A(1,2);Point B(A); //拷贝构造函数被调用cout<<B.GetX()<<endl;return 0;}

b.若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。例如:

   void fun1(Point p){   cout<<p.GetX()<<endl;} int main(){   Point A(1,2);fun1(A); //调用拷贝构造函数return 0;}

c.当函数的返回值是类对象时,系统自动调用拷贝构造函数。例如:

   Point fun2(){    Point A(1,2);return A; //调用拷贝构造函数}int main(){Point B;B=fun2();return 0;}

最后这种情况怎么调用的拷贝构造函数呢?对象A是局部对象,在fun2函数执行完就释放了,那怎么将它拷贝给对象B呢?编译器在执行B=fun2()时会创建一个临时的无名对象,在执行return A时实际上是调用了拷贝构造函数将A的值拷贝到了临时对象中,A就释放了,然后将临时对象的值再拷贝到对象B中。

3.析构函数

自然万物都是有生有灭的,类的对象也一样是有生命周期的,一样会消亡。鸡啄米给大家讲一种情况:如果在函数中声明了一个对象,那么在这个函数运行完返回调用函数时,声明的对象也会释放,就像上面说的fun2函数中对象A那样。

在对象释放时都有什么工作要做呢?我们经常遇到的情况就是:构造函数时动态申请了一些内存单元,在对象释放时就要同时释放这些内存单元。动态分配内存的知识后面鸡啄米会讲。

析构函数和构造函数的作用是相反的,它会在对象被删除之前做一些清理工作。析构函数是在对象要被删除时由系统自动调用的,它执行完后对象就消失了,分配的内存空间也释放了。

析构函数是类的一个公有函数成员,它的名称是在类名前加“~”形成,不能有返回值,大家注意下,它和构造函数不同的是它不能有任何形参。如果没有定义析构函数系统也会自动生成一个默认析构函数,默认析构函数也不会做任何工作。一般如果我们想在对象被删除之前做什么工作就可以把它写到析构函数里。

鸡啄米还是在上面那个坐标点类中加入析构函数给大家看下析构函数怎么用:

   class Point{     public:Point(int xx, int yy);~Point();//...其他函数原型private:int X, int Y;char *p;};

下面是构造函数和析构函数的实现:

   Point::Point(int xx,int yy){     X=xx;   Y=yy;p=new char[20];     // 构造函数中动态分配char型内存}Point::~Point(){delete []char;      // 在类析构时释放之前动态分配的内存}//...其他函数的实现略

new和delete的用法鸡啄米后面会讲,这里只是让大家看下析构函数有什么作用。

构造函数和析构函数是大家C++编程入门时必须掌握的内容,很多公司笔试或面试时都会考到,大家掌握好啊,呵呵。鸡啄米谢谢大家关注我的教程!我们一起努力!

思考:

1. 什么是构造函数?在什么时候被调用?

2. 拷贝构造函数的定义?什么时候会调用拷贝构造函数?

3. 析构函数的定义?什么时候会调用析构函数?

C++编程入门系列之十四(类与对象:构造函数和析构函数)相关推荐

  1. 鸡啄米之VS2010/MFC编程入门之二十四(常用控件:列表框控件ListBox)

    目录 一.目的: 1.点击列表框某个变量后,编辑框就显示出来这个变量名字 一.参考: 1.VS2010/MFC编程入门之二十四(常用控件:列表框控件ListBox) ①总结:good:亲测有效,适合多 ...

  2. jquery audio没有声音_Python实用案例编程入门:第十四章 通过声音控制您的计算机

    本章的主题为通过声音来控制您的电脑.当下的语音识别已经相对比较成熟,比如有的车载系统,或手机都支持语音识别,您可以通过声音来下达指令.比如您告诉导航系统"我要去北京",它会自动帮您 ...

  3. LSTM长短记,长序依赖可追忆(深度学习入门系列之十四)

    摘要:如果你是一名单身狗,不要伤心,或许是因为你的记忆太好了.有时,遗忘是件好事,它让你对琐碎之事不再斤斤计较.然而每当自己记不住单词而"问候亲人"时,也确实气死个人.于是你懂得了 ...

  4. 【深度学习之美】LSTM长短记,长序依赖可追忆(入门系列之十四)

    14.1 遗忘是件好事还是坏事? 如果我问你,遗忘,是件好事,还是坏事? 或许你会说,当然是件坏事啊,我可羡慕记忆力好的人了. 可我要告诉你,如果你到现在还记得,两岁时,隔壁家的小女孩"横刀 ...

  5. [unreal4入门系列之十四] 在UE4中添加碰撞触发事件

    一.在HUD中显示消息 1) 在MyHUD.h中定义一个结构来表示我们的消息: #pragma once #include "GameFramework/HUD.h" #inclu ...

  6. 【ASE入门学习】ASE入门系列二十四——轴向溶解

    武器出现消失效果复刻,涉及知识点:轴向溶解.光边溶解.Surface材质.UV2(第二套UV).Animation动画制作.简单光粒子制作 至此自发光四个部分说明完毕(第一部分是自反光贴图自身)把这4 ...

  7. Go入门系列(十八) 反射、包和测试工具

    本系列文章目录 展开/收起 Go入门系列(一) 初识Go语言 Go入门系列(二) 变量.指针.数据类型简介和作用域 Go入门系列(三) 基础类型--整型.浮点型.布尔类型和字符串 Go入门系列(四) ...

  8. 【深度学习之美】卷地风来忽吹散,积得飘零美如画(入门系列之十)

    系列文章: 一入侯门"深"似海,深度学习深几许(深度学习入门系列之一) 人工"碳"索意犹尽,智能"硅"来未可知(深度学习入门系列之二) 神经 ...

  9. springboot mybatis ehcache_SpringBoot入门建站全系列(十四)集成Redis缓存

    SpringBoot入门建站全系列(十四)集成Redis缓存 一.概述 本地缓存,就是使用应用内使用本地内存将数据暂缓存储,一般数据库的查询如果不怎么改动,可以用本地缓存暂存. 远程缓存,比如redi ...

最新文章

  1. 深度学习:知识回收(Lecture3+4 PLA+Decision Tree)
  2. Apache 编译安装
  3. 于明:必应发力海外业务 中国搜索营销市场暗流涌动
  4. 信息论霍夫曼编码c语言,Huffman 信息论与编码 - 下载 - 搜珍网
  5. WAMPSERVER 启动后打开LOCALHOST是一张IIS7的图片的解决
  6. 网络协议从入门到底层原理(5)传输层(UDP、TCP - 可靠传输、流量控制、拥塞控制、建立连接、释放连接)
  7. 2.Dockerfile
  8. leetcode77
  9. reset.css下载
  10. android中表情功能实现,android sina 微博表情功能的实现
  11. 如何用计算机对cad的草图,cad文件导入草图大师的方法步骤
  12. python单例模式例子_python单例模式实例分析
  13. vue 分享给好友 点击分享按钮_点击网页分享按钮,触发微信分享功能
  14. 百度搜索引擎结果网址参数搜索历史记录(rsv_sug)
  15. 2019-行远自迩,登高自卑
  16. 移动硬盘 无法读取 插入电脑没反应 无法识别 怎么办
  17. 计算机耍人,抖音中的连环套路耍人问题
  18. 科学计算法(e/E表示规则)
  19. 解决导入网关gateway依赖爆红
  20. 高一凡-数据结构第1章-绪论

热门文章

  1. 上最有效懒人减肥法 喝水减肥不易反弹快试试吧
  2. CSUST Online Judge4031 最喜欢的数
  3. handlebar.js模板引擎(轻页面小工程可用)
  4. mysql做用户满意度调查系统_MySQL分析工作满意度
  5. 同学:你因作业作弊已被AI抓获,Python制作一款AI检测抄袭小脚本。
  6. python的wxpy库_Python库学习 wxpy - 微信机器人
  7. openwrt frpc问题
  8. 番茄小说app - xl,xa,xg,xk,xh,xm参数分析
  9. 谈谈iceCode代码高亮插件的开发问题,由我们国人开发代码高亮插件!
  10. Qt connect不明确