C++解析(12):初始化列表与对象构造顺序、析构顺序
0.目录
1.类成员的初始化
2.类中的const成员
3.对象的构造顺序
4.对象的析构顺序
5.小结
1.类成员的初始化
类中是否可以定义const成员?
下面的类定义是否合法?如果合法,ci的值是什么,存储在哪里?

(会报错)
C++中提供了初始化列表对成员变量进行初始化
语法规则:

注意事项:
- 成员的初始化顺序与成员的声明顺序相同
- 成员的初始化顺序与初始化列表中的位置无关
- 初始化列表先于构造函数的函数体执行
证明成员的初始化顺序与成员的声明顺序相同,而与初始化列表中的位置无关:
#include <stdio.h>
class Value
{
private:
int mi;
public:
Value(int i)
{
printf("i = %d\n", i);
mi = i;
}
int getI() { return mi; }
};
class Test
{
private:
Value m2;
Value m3;
Value m1;
public:
Test() : m1(1), m2(2), m3(3)
{
printf("Test::Test()\n");
}
};
int main()
{
Test t;
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
i = 2
i = 3
i = 1
Test::Test()
2.类中的const成员
类中的const成员:
- 类中的const成员会被分配空间的
- 类中的const成员的本质是只读变量
- 类中的const成员只能在初始化列表中指定初始化
编译器无法直接得到const成员的初始值,因此无法进入符号表成为真正意义上的常量。
证明类中的const成员的本质是只读变量:
#include <stdio.h>
class Value
{
private:
int mi;
public:
Value(int i)
{
printf("i = %d\n", i);
mi = i;
}
int getI()
{
return mi;
}
};
class Test
{
private:
const int ci;
Value m2;
Value m3;
Value m1;
public:
Test() : m1(1), m2(2), m3(3), ci(100)
{
printf("Test::Test()\n");
}
int getCI()
{
return ci;
}
int setCI(int v)
{
int* p = const_cast<int*>(&ci);
*p = v;
}
};
int main()
{
Test t;
printf("t.ci = %d\n", t.getCI());
t.setCI(10);
printf("t.ci = %d\n", t.getCI());
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
i = 2
i = 3
i = 1
Test::Test()
t.ci = 100
t.ci = 10
初始化与赋值不同:
- 初始化:对正在创建的对象进行初值设置
- 赋值:对已经存在的对象进行值设置
3.对象的构造顺序
3.1 局部对象的构造顺序
对于局部对象——当程序执行流到达对象的定义语句时进行构造
下面程序中的对象构造顺序是什么?

示例:
#include <stdio.h>
class Test
{
private:
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(int i): %d\n", mi);
}
Test(const Test& obj)
{
mi = obj.mi;
printf("Test(const Test& obj): %d\n", mi);
}
};
int main()
{
int i = 0;
Test a1 = i;
while( i < 3 )
{
Test a2 = ++i;
}
if( i < 4 )
{
Test a = a1;
}
else
{
Test a(100);
}
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
Test(int i): 0
Test(int i): 1
Test(int i): 2
Test(int i): 3
Test(const Test& obj): 0
以下程序改变了程序的执行流,有严重的bug,但是不同的编译器有不同的处理结果,有些编译器不会报错,一定要注意这种问题!
#include <stdio.h>
class Test
{
private:
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(int i): %d\n", mi);
}
Test(const Test& obj)
{
mi = obj.mi;
printf("Test(const Test& obj): %d\n", mi);
}
int getMi()
{
return mi;
}
};
int main()
{
int i = 0;
Test a1 = i; // Test(int i): 0
while( i < 3 )
{
Test a2 = ++i; // Test(int i): 1, 2, 3
}
goto End;
Test a(100);
End:
printf("a.mi = %d\n", a.getMi());
return 0;
}
3.2 堆对象的构造顺序
对于堆对象:
- 当程序执行流到达new语句时创建对象
- 使用new创建对象将自动触发构造函数的调用
下面程序中的对象构造顺序是什么?

示例:
#include <stdio.h>
class Test
{
private:
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(int i): %d\n", mi);
}
Test(const Test& obj)
{
mi = obj.mi;
printf("Test(const Test& obj): %d\n", mi);
}
int getMi()
{
return mi;
}
};
int main()
{
int i = 0;
Test* a1 = new Test(i); // Test(int i): 0
while( ++i < 10 )
if( i % 2 )
new Test(i); // Test(int i): 1, 3, 5, 7, 9
if( i < 4 )
new Test(*a1);
else
new Test(100); // Test(int i): 100
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
Test(int i): 0
Test(int i): 1
Test(int i): 3
Test(int i): 5
Test(int i): 7
Test(int i): 9
Test(int i): 100
3.3 全局对象的构造顺序
对于全局对象:
- 对象的构造顺序是不确定的
- 不同的编译器使用不同的规则确定构造顺序
(要避开全局对象之间的相互依赖!)
4.对象的析构顺序
单个对象创建时析构函数的调用顺序——析构函数与对应的构造函数的调用顺序相反:
- 调用父类的构造过程
- 调用成员变量的构造函数(调用顺序与声明顺序相同)
- 调用类自身的构造函数
多个对象析构时——析构顺序与构造顺序相反:
- 对于栈对象和全局对象,类似于入栈与出栈的顺序,最后构造的对象被最先析构!!
- 堆对象的析构发生在使用delete的时候,与delete的使用顺序相关!!
5.小结
- 类中可以使用初始化列表对成员进行初始化
- 初始化列表先于构造函数体执行
- 类中可以定义const成员变量
- const成员变量必须在初始化列表中指定初值
- const成员变量为只读变量
- 局部对象的构造顺序依赖于程序的执行流
- 堆对象的构造顺序依赖于new的使用顺序
- 全局对象的构造顺序是不确定的
- 对象的析构顺序与构造顺序相反
C++解析(12):初始化列表与对象构造顺序、析构顺序的更多相关文章
- C++浅析——继承类中构造和析构顺序
先看测试代码,CTEST 继承自CBase,并包含一个CMember成员对象: static int nIndex = 1; class CMember { public: CMember() { p ...
- C++ //继承中构造和析构顺序
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Base 6 { 7 pu ...
- Java内存结构、类的初始化、及对象构造过程
概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...
- 再探Delphi2010 Class的构造和析构顺序
发了上一篇博客.盒子上有朋友认为Class的构造和析构延迟加载.是在Unit的初始化后调用的Class的构造.在Unit的反初始化前调用的Class的析构函数. 为了证明一下我又做了个试验 unit ...
- C++语法小记---继承中的构造和析构顺序
继承中构造和析构的顺序 先父母,后客人,最后自己 静态变量和全局变量在最开始 析构和构造的顺序完全相反 #include <iostream> #include <string> ...
- C++ 类成员的构造和析构顺序
我想对面向对象有了解的童鞋应该不会对类和对象感到陌生吧 ! 对象并不是突然建立起来的,创建对象必须时必须同时创建父类以及包含于其中的对象.C++遵循如下的创建顺序: (1)如果某个类具体基类,执行基类 ...
- C++初始化列表各情况分析
今天回顾了下C++初始化列表的知识,接下来我对这一知识作一总结. 我们在定义了一个类的时候,需要对类的成员进行初始化.关于初始化,有两种方法,一种在初始化列表中进行,另一种就是在构造函数中进行,对于这 ...
- C++中初始化列表的使用(总结)
原文链接 https://www.cnblogs.com/dishengAndziyu/p/10906081.html 参考链接:https://www.cnblogs.com/laiqun/p/57 ...
- C++类构造函数初始化列表
C++类构造函数初始化列表 构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式.例如: class CExample {public: ...
随机推荐
- 成都Uber优步司机奖励政策(4月14日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 「PKUWC2018」Minimax
题面 题解 强势安利一波巨佬的$blog$ 线段树合并吼题啊 合并的时候要记一下$A$点权值小于$l$的概率和$A$点权值大于$r$的概率,对$B$点同样做 时空复杂度$\text O(nlogw)$ ...
- Javascript库,前端框架(UI框架),模板引擎
JavaScript库:JQuery,undoscore,Zepto 纯Javascript语言封装, 前端框架(UI框架):Bootstrap,Foundation,Semantic UI,Pure ...
- js插件实现一键复制功能
clipboard.js 可以实现纯 JS 的从浏览器复制文本到系统剪贴板的功能. 使用方法: 1. 下载 clipboard.js,并在页面中引入该插件.clipboard.js 下载地址: htt ...
- ubuntu/linux系统中安装jdk以及eclipse(附图解详细步骤)
1.首先得先下载JDK和eclipsejdk下载网址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-21 ...
- Spring学习(3):Spring概述(转载)
1. Spring是什么? Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发. 在面向对象思想中 ...
- Centos7下安装Oracle11g r2
我的centos7是在virtualbox下安装的,安装Oracle安装了好久好久,最开始的时候在网上找的两个文章,按照步骤装,有一篇写着装的时候有灰色的竖线,直接按space键或者鼠标右键close ...
- 微软职位内部推荐-Senior Software Engineer II-Search
微软近期Open的职位: Do you want to work on a fast-cycle, high visibility, hardcore search team with ambitio ...
- eBay推Winit海外仓 鼓励卖家拓展北美市场
[亿邦动力网讯]2月11日消息,日前,跨境电商平台eBay与外贸电商服务商万邑通(Winit)合作,针对平台卖家推出了Winit美国海外仓,鼓励卖家拓展北美市场. 亿邦动力网获悉,Winit美国海外仓 ...
- OOP 1.5 类和对象的基本概念与用法1
1.定义 面向对象的基本特点:抽象.封装.继承.多态 面向对象程序设计方法:将某类客观事物的共同特点归纳出来,形成一个数据结构 抽象:将事物所能进行的行为归纳出来,形成一个个函数,这些函数可以用来操作 ...