以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。
对象数组,即数组的每个元素都是某个类的对象。
1、对象数组中的每个元素都需要用构造函数初始化,具体哪些元素用哪些构造函数初始化,取决于定义数组时的写法。
请看下面的例子:
- #include
- using namespace std;
-
- class CSample{
- public:
- CSample(){ //构造函数 1
- cout<<"Constructor 1 Called"<
- }
- CSample(int n){ //构造函数 2
- cout<<"Constructor 2 Called"<
- }
- };
-
- int main(){
- cout<<"stepl"<
- CSample arrayl[2]; //1,1
- //类似于CSample arrayl[0](),arrayl[1]() ? 有这种写法吗?
-
- cout<<"step2"<
- CSample array2[2] = {4, 5};//2,2
- //类似于CSample arrayl[0](4),arrayl[1](5) ? 有这种写法吗?
-
- cout<<"step3"<
- CSample array3[2] = {3};//2,1
-
- cout<<"step4"<
- CSample* array4 = new CSample[2];//1,1
- delete [] array4;
-
- return 0;
- }
- stepl
- Constructor 1 Called
- Constructor 1 Called
- step2
- Constructor 2 Called
- Constructor 2 Called
- step3
- Constructor 2 Called
- Constructor 1 Called
- step4
- Constructor 1 Called
- Constructor 1 Called
step1的 array1 数组中的两个元素没有指明如何初始化,那么默认调用无参构造函数初始化,因此输出两行 Constructor 1 Called。
step2的 array2 数组进行了初始化,初始化列表 {4, 5} 可以看作用来初始化两个数组元素的参数,所以 array2[0] 以 4 为参数,调用构造函数 2 进行初始化;array2[1] 以 5 为参数,调用构造函数 2 进行初始化。这导致输出两行 Constructor 2 Called。
step3的 array3 指出了 array3[0] 的初始化方式,没有指出 array3[1] 的初始化方式,因此分别用构造函数 2 和构造函数 1 进行初始化。
step4动态分配了一个 CSample 数组,其中有两个元素,没有指出和参数有关的信息,因此这两个元素都用无参构造函数初始化。
2、在构造函数有多个参数时,数组的初始化列表中要显式地包含对构造函数的调用。
例如下面的程序:
- class CTest{
- public:
- CTest(int n){ } //构造函数(1)
- CTest(int n, int m){ } //构造函数(2)
- CTest(){ } //构造函数(3)
- };
- int main(){
- //三个元素分别用构造函数(1)、(2)、(3) 初始化
- CTest arrayl[3] = { 1, CTest(1,2) };//像{1, (1,2)}这样行不行呢?
-
- //三个元素分别用构造函数(2)、(2)、(1)初始化
- CTest array2[3] = { CTest(2,3), CTest(1,2), 1};
-
- //两个元素指向的对象分别用构造函数(1)、(2)初始化
- CTest* pArray[3] = { new CTest(4), new CTest(1,2) }; //第13行
-
- return 0;
- }
上面程序中比较容易令初学者困惑的是第 13 行。
pArray 数组是一个指针数组,其元素不是 CTest 类的对象,而是 CTest 类的指针。第 13 行对 pArray[0] 和 pArray[1] 进行了初始化,把它们初始化为指向动态分配的 CTest 对象的指针,而这两个动态分配出来的 CTest 对象又分别是用构造函数(1)和构造函数(2)初始化的。pArray[2] 没有初始化,其值是随机的,不知道指向哪里。
第 13 行生成了两个 CTest 对象,而不是三个,所以也只调用了两次 CTest 类的构造函数。
二、成员对象与封闭类
1、一些概念理解
如果一个类的成员变量是另一个类的对象,则称该成员变量为“成员对象”,而包含成员对象的类叫封闭类(enclosed class)。
2、封闭类的对象的初始化
创建封闭类的对象时,它包含的成员对象也需要被创建,这就会引发成员对象构造函数的调用。成员对象的构造函数可能有很多个(即函数重载),那如何让编译器知道,成员对象到底是用哪个构造函数进行初始化?这就需要借助封闭类构造函数的初始化列表。
一个简单的示例如下:
- #include
- using namespace std;
-
- //1、轮胎类
- class Tyre{
- public:
- Tyre(int radius, int width);//轮胎类构造函数的声明
- void show() const;
- private:
- int m_radius; //半径
- int m_width; //宽度
- };
- //轮胎类构造函数的定义
- Tyre::Tyre(int radius, int width) : m_radius(radius), m_width(width){ }
- void Tyre::show() const {
- cout << "轮毂半径:" << this->m_radius << "吋" << endl;
- cout << "轮胎宽度:" << this->m_width << "mm" << endl;
- }
-
- //2、引擎类
- class Engine{
- public:
- Engine(float displacement = 2.0);//引擎类构造函数的声明
- void show() const;
- private:
- float m_displacement;
- };
- //引擎类构造函数的定义
- Engine::Engine(float displacement) : m_displacement(displacement) {}
- void Engine::show() const {
- cout << "排量:" << this->m_displacement << "L" << endl;
- }
-
- //3、汽车类
- class Car{
- public:
- Car(int price, int radius, int width);//汽车类构造函数的声明
- void show() const;
- private:
- int m_price; //价格
- Tyre m_tyre;
- Engine m_engine;
- };
- //汽车类构造函数的定义
- Car::Car(int price, int radius, int width): m_price(price), m_tyre(radius, width){ };
- //指明m_tyre对象的初始化方式
- void Car::show() const {
- cout << "价格:" << this->m_price << "¥" << endl;
- this->m_tyre.show();
- this->m_engine.show();
- }
-
- int main()
- {
- Car car(200000, 19, 245);//第51行
- car.show();
- return 0;
- }
- 价格:200000¥
- 轮毂直径:19吋
- 轮胎宽度:245mm
- 排量:2L
封闭类构造函数的初始化列表,其写法如下:
- 封闭类的类名::封闭类的构造函数名(参数表): 成员变量名(参数表),…,成员对象名(参数表)
- {
- //TODO:
- }
对于封闭类Car,它有一个成员变量m_price,两个成员对象m_tyre 和 m_engine。而且编译器知道第 51 行的 car 这个对象是用 Car(int price, int radius, int width) 这个构造函数进行初始化的。
(1)对于基本类型的成员变量,比如成员变量 m_price 是 int 类型,其“参数表”中只有一个值,就是初始值,在调用构造函数时,会把这个初始值直接赋给成员变量。比如Car类构造函数的初始化列表中,将初始值 price 赋值给成员变量 m_price。
(2)对于成员对象,“参数表”中存放的是构造函数的参数,它可能只有一个值,也可能有多个值,它指明了该成员对象如何被初始化。比如Car类构造函数的初始化列表中,m_tyre(radius, width)告诉编译器,应该以 radius 和 width 作为参数传入构造函数 Tyre(int radius, int width) 中,来初始化m_tyre这个对象。
(3)这里没有说明 m_engine 该如何处理,此时编译器就认为 m_engine 应该用 Engine 类的无参构造函数初始化,而 Engine 类确实有一个无参构造函数(设置了固定参数而视为无参)。
总之,生成封闭类对象的语句,一定要让编译器能够弄明白其成员对象是如何初始化的,否则就会编译错误。在上面的程序中,如果 Car 类的构造函数没有初始化列表,那么第 51 行就会编译出错,因为编译器不知道该如何初始化 car.m_tyre 对象,因为 Tyre 类没有无参构造函数,而编译器又找不到用来初始化 car.m_tyre 对象的参数。
3、成员对象的消亡
封闭类对象生成时,先执行所有成员对象的构造函数,然后才执行封闭类自己的构造函数。成员对象构造函数的执行次序和成员对象在类定义中的次序一致,与它们在构造函数初始化列表中出现的次序无关。
当封闭类对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数,成员对象析构函数的执行次序和构造函数的执行次序相反,即先构造的后析构,这是 C++ 处理此类次序问题的一般规律。
- #include
- using namespace std;
-
- class Tyre {
- public:
- Tyre() { cout << "Tyre constructor" << endl; }
- ~Tyre() { cout << "Tyre destructor" << endl; }
- };
-
- class Engine {
- public:
- Engine() { cout << "Engine constructor" << endl; }
- ~Engine() { cout << "Engine destructor" << endl; }
- };
-
- class Car {
- private:
- Engine engine;
- Tyre tyre;
- public:
- Car() { cout << "Car constructor" << endl; }
- ~Car() { cout << "Car destructor" << endl; }
- };
-
- int main() {
- Car car;
- return 0;
- }
- Engine constructor
- Tyre constructor
- Car constructor
- Car destructor
- Tyre destructor
- Engine destructor
-
相关阅读:
从零手写实现 nginx-13-nginx.conf 是 HOCON 的格式吗?
uni-app实现点击复制按钮 复制内容
Windows 系统服务器部署jar包时,推荐使用winsw,将jar包注册成服务,并设置开机启动。
java MessageDigest 实现加密算法
【工具】typora的一些配置
1.BERT
python_data_analysis_and_mining_action-master-5
【安全】网络安全态势感知
git使用全解析 | git的原理 配置 基础使用 分支 合并
Pytorch模型训练实用教程学习笔记:一、数据加载和transforms方法总结
-
原文地址:https://blog.csdn.net/oqqHuTu12345678/article/details/133818180