当前位置: 首页 > news >正文

C++编程学习(第37天)

对象的初始化

需要对类对象进行初始化

不能在声明类时对数据成员初始化,如果一个类中所有的成员都是公用的,则可以在定义对象时对数据成员进行初始化。

用构造函数实现数据成员的初始化

C++提供了构造函数来处理对象的初始化。构造函数是一种特殊的成员函数,与其它成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。构造函数是在声明类的时候由类的设计者定义的,程序用户只须在定义对象的同时指定数据成员的初值即可。

构造函数的名字必须与类名同名,而不能任意命名,以便编译系统能识别它并把它作为构造函数处理,它不具有任何类型,不返回任何值。

例1:用构造函数为对象的数据成员赋初值

#include <iostream>
using namespace std;class Time						//声明Time类
{
public:							//公用函数Time()						//定义构造成员函数,函数名与类名相同				{hour = 12;				//利用构造函数对对象中的数据成员赋初值minute = 12;sec = 12;}void set_time();			//成员函数声明void show_time();			//成员函数声明
private:						//私有声明int hour, minute, sec;		//私有数据
};void Time::set_time()
{cin >> hour >> minute >> sec;
}void Time::show_time()
{cout << hour << ":" << minute << ":" << sec << endl;
}int main()
{Time t1;t1.set_time();t1.show_time();Time t2;t2.show_time();return 0;
}

在类中定义了构造函数Time,它和所在的类同名,在建立对象时会自动执行构造函数,赋值语句是写在构造函数的函数体中的,只有在调用构造函数时才执行这些赋值语句,对当前对象中的数据成员赋值。

也可以只在类内对构造函数进行声明而在类外定义构造函数。在类外定义构造成员函数,要加上类名Time和域限定符“::”。

需要注意的是

1、构造函数调用时机:在建立类对象时自动调用构造函数

2、构造函数没有返回值,也没有类型,它的作用只是对对象进行初始化,因此不需要在定义构造函数时声明类型。

3、构造函数不需要用户调用,也不能被用户调用。

4、可以用一个类对象初始化另一个类对象。

5、在构造函数的函数体中不仅可以对数据成员赋初值,而且可以包含其它语句,如cout语句,一般不提倡加入域初始化无关的内容。

6、如果用户没自己没有定义构造函数,则C++系统会自动生成一个构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行初始化操作。

7、构造函数有不同的形式,以便用于不同情况的数据初始化。

带参数的构造函数

带参数的构造函数,在调用不同对象的构造函数时,从外面将不同的数据传递给构造函数,以实现对不同对象的初始化。

构造函数首部的一般形式为

构造函数名(类型1 形参1,类型2 形参2,···)

实参是在定义对象时给出的,定义对象的一般形式为

类名 对象名(实参1,实参2,···);

在建立对象时把实参的值传递给构造函数相应的形参,把它们作为数据成员的初值。

例2:有两个长方柱,求它们的体积。编写一个基于对象的程序,在类中用带参数的构造函数对数据成员初始化。

#include <iostream>
using namespace std;class Box
{
public:Box(int, int, int);int volume();
private:int length, width, height;
};Box::Box(int len, int w, int h)
{length = len;width = w;height = h;
}int Box::volume()
{return(length * width * height);
}int main()
{Box box1(30, 10, 20);cout << "volume1 = " << box1.volume() << endl;Box box2(3, 1, 2);cout << "volume2 = " << box2.volume() << endl;return 0;
}
在构造函数中用参数初始化表对数据成员初始化

带有参数初始化表的构造函数的一般形式为

类名::构造函数名([参数表])[:成员初始化表]{[构造函数体]}

用参数的初始化表法可以减少函数体的长度,使结构函数显得精炼简单,这样就可以直接在类体定义构造函数。

如果数据成员是数组,则应当在构造函数的函数体中用语句对其赋值,而不能在参数初始化表中对其初始化。

对构造函数进行重载

在一个类中可以定义多个构造函数,以便为对象提供不同的初始化的方法,供用户选用,这些构造函数具有相同的名字,而参数的个数或参数的类型不相同,这称为构造函数的重载。

例3:定义两个构造函数,一个有参数,一个无参数

#include <iostream>
using namespace std;class Box
{
public:Box();Box(int h, int w, int len) :height(h), width(w), length(len) {}int volume();
private:int height, width, length;
};Box::Box()
{height = 10;width = 10;length = 10;
}int Box::volume()
{return(height * width * length);
}int main()
{Box box1;cout << "volume1 = " << box1.volume() << endl;Box box2(10, 30, 20);cout << "volume2 = " << box2.volume() << endl;return 0;
}

需要注意的是

1、在建立对象时不必给出实参的构造函数,称为默认构造函数,无参构造函数属于默认构造函数,一个类只能有一个默认构造函数。如果用户未定义构造函数,则系统会自动提供一个默认构造函数,但它的函数体是空的,不起初始化作用,如果用户希望在创建对象时就能使数据成员有初值,就必须自己定义构造函数。

2、如果在建立对象时选用的是无参构造函数,应注意正确书写定义对象的语句。

3、尽管在一个类中可以包含多个构造函数,但是对于每一个对象来说,建立对象时只执行其中一个构造函数,并非每个构造函数都被执行。

构造函数中可以使用默认参数

构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值。

例4:使用默认参数编写程序

#include <iostream>
using namespace std;class Box
{
public:Box(int h = 10, int w = 10, int len = 10);int volume();
private:int height, width, length;
};Box::Box(int h, int w, int len)
{height = h;width = w;length = len;
}int Box::volume()
{return(height * width * length);
}int main()
{Box box1;cout << "v1 = " << box1.volume() << endl;Box box2(15);cout << "v2 = " << box2.volume() << endl;Box box3(15,30);cout << "v3 = " << box3.volume() << endl;Box box4(15,30,20);cout << "v4 = " << box4.volume() << endl;return 0;
}

需要注意的是

1、应在声明构造函数时指定默认值,而不能只在定义构造函数时指定默认值

2、在声明构造函数时,形参名可以省略

3、如果构造函数的全部参数都指定了默认值,则在定义对象时可以给一个或几个实参,也可以不给出实参,由于不需要实参也可以调用构造函数,因此全部参数都指定了默认值的构造函数也属于默认构造函数。一个类只能有一个默认构造函数,也就是说,可以不用参数而调用的构造函数,一个类只能有一个。

4、在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。

利用析构函数进行清理工作

析构函数也是一种特殊的成员函数,它的作用与构造函数相反,它的名字是类名的前面加一个“~”符号。在C++中“~”是位取反运算符,故析构函数是与构造函数作用相反的函数。

当对象的生命周期结束时,会自动执行析构函数,即以下四种情况

1、如果在一个函数中定义了一个对象,当这个函数被调用结束时,对象应释放,在对象释放前自动执行析构函数

2、静态局部对象在函数调用结束时对象不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数。

3、如果定义了一个全局对象,则在程序的流程离开其作用域时,调用该全局对象的析构函数

4、如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。

析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。

析构函数不返回任何值,没有函数类型,也没有函数参数,因此不能被重载,一个类可以有多个构造函数,但是只能有一个析构函数。

析构函数的作用并不仅限于释放资源方面,它还可以被用来执行“用户希望在最后一次使用对象之后所执行的任何操作”。

一般情况下,类的设计者应当在声明类的同时定义析构函数,以指定如何完成清理工作,如果用户没有定义析构函数,C++编译系统会自动生成一个析构函数,但它只是徒有析构函数的名称和形式,实际上什么操作都不进行。

例5:包含构造函数和析构函数的C++程序。

#include <iostream>
#include <string>
using namespace std;class Student
{
public:Student(int n, string nam, char s) {num = n;name = nam;sex = s;cout << "构造函数!" << endl;}~Student(){cout << "析构函数!" << endl;}void display(){cout << "num: " << num << endl;cout << "name: " << name << endl;cout << "sex: " << sex << endl;}
private:int num;string name;char sex;
};int main()
{Student stu1(1001, "zhangsan", 'a');stu1.display();Student stu2(1002, "lisi", 'b');stu2.display();return 0;
}
调用构造函数和析构函数的顺序

在一般情况下,调用析构函数的顺序正好与调用构造函数的顺序相反,最先被调用的构造函数,其对应的析构函数最后被调用,最后被调用的构造函数,其对应的析构函数最先被调用,相当于一个栈,先进后出。这是对同一类存储类别的对象而言的,并不是在任何情况下都是按这一原则处理的。对象可以在不同的作用域中定义,可以有不同的存储机制,这些会影响调用构造函数的析构函数的时机。

系统调用构造函数和析构函数的时机如下:

1、如果在全局范围中定义对象,那么它的构造函数在本文件模块中的所有函数执行前调用,但如果一个程序包含多个文件,而在不同的文件中都定义了全局对象,则这些对象的构造函数的执行顺序是不确定的。当main函数执行完毕或调用exit函数时,调用析构函数。

2、如果定义的是局部自动对象,则在建立对象时调用其构造函数,如果对象所在的函数多次调用,则在每次建立对象时都要调用构造函数,在函数调用结束、对象释放时先调用析构函数。

3、如果在函数中定义静态局部对象,则只在程序第一次调用此函数定义对象时调用构造函数一次,在调用函数结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时才调用析构函数。

http://www.dtcms.com/a/499361.html

相关文章:

  • 手机壳在线设计网站网站建设座谈会上的发言
  • 北京北排建设公司招标网站电子商务网站建设规划方案论文
  • hot100练习-10
  • WebSocket实现网站点赞通知
  • NotoSansCJK和SourceHanSansSC两款字体区别浅谈
  • 串口屏学习
  • Conda 环境激活失败或 PATH 优先级被主 Anaconda 覆盖
  • 什么建网站免费做网站代码审计哪个工具比较好
  • AI协同编程架构师:驾驭智能体社会的元语言创造者
  • 肇庆建网站服务腾讯建站平台官网
  • 聊聊 Unity(小白专享、C# 小程序 之 播放器)
  • [MLflow] CI/CD | 测试自动格式化工作流 | Ruff格式化器 | 预提交钩子配置
  • 数据结构——二十四、图(王道408)
  • C#获取钉钉平台考勤记录
  • Java JVM “调优” 面试清单(含超通俗生活案例与深度理解)
  • opencv gpu cuda python c++版本测试代码
  • 建设旅游门户网站安徽网站建设推荐 晨飞网络
  • 鸿蒙Next Wear Engine Kit:打造无缝连接的穿戴应用体验
  • 哪里有免费的网站推广软件网站源码上传完后怎么做
  • 快手测开面试题总结合并版(按分类标注序号+出现频率)
  • P1005 [NOIP 2007 提高组] 矩阵取数游戏
  • JAVA面试复习笔记(待完善)
  • 七、WEB APIs(二)
  • LLMs-from-scratch :多种字节对编码(BPE)对比
  • 济南哪里有网站建设公司网站类网站开发源代码
  • 做笔记的网站源码wordpress手机版论坛
  • 网站推广有哪些举措域名需要跟网站名称一致么
  • 具身神经-机器人通讯架构与实现系列
  • [GO]gin框架:ShouldBindJSON与其他常见绑定方法
  • KUKA库卡焊接机器人二氧化碳节气