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.对象的析构顺序

单个对象创建时析构函数的调用顺序——析构函数与对应的构造函数的调用顺序相反:

  1. 调用父类的构造过程
  2. 调用成员变量的构造函数(调用顺序与声明顺序相同)
  3. 调用类自身的构造函数

多个对象析构时——析构顺序与构造顺序相反:

  • 对于栈对象和全局对象,类似于入栈与出栈的顺序,最后构造的对象被最先析构!!
  • 堆对象的析构发生在使用delete的时候,与delete的使用顺序相关!!

5.小结

  • 类中可以使用初始化列表对成员进行初始化
  • 初始化列表先于构造函数体执行
  • 类中可以定义const成员变量
  • const成员变量必须在初始化列表中指定初值
  • const成员变量为只读变量
  • 局部对象的构造顺序依赖于程序的执行流
  • 堆对象的构造顺序依赖于new的使用顺序
  • 全局对象的构造顺序是不确定的
  • 对象的析构顺序与构造顺序相反

C++解析(12):初始化列表与对象构造顺序、析构顺序的更多相关文章

  1. C++浅析——继承类中构造和析构顺序

    先看测试代码,CTEST 继承自CBase,并包含一个CMember成员对象: static int nIndex = 1; class CMember { public: CMember() { p ...

  2. C++ //继承中构造和析构顺序

    1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Base 6 { 7 pu ...

  3. Java内存结构、类的初始化、及对象构造过程

    概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...

  4. 再探Delphi2010 Class的构造和析构顺序

    发了上一篇博客.盒子上有朋友认为Class的构造和析构延迟加载.是在Unit的初始化后调用的Class的构造.在Unit的反初始化前调用的Class的析构函数. 为了证明一下我又做了个试验 unit ...

  5. C++语法小记---继承中的构造和析构顺序

    继承中构造和析构的顺序 先父母,后客人,最后自己 静态变量和全局变量在最开始 析构和构造的顺序完全相反 #include <iostream> #include <string> ...

  6. C++ 类成员的构造和析构顺序

    我想对面向对象有了解的童鞋应该不会对类和对象感到陌生吧 ! 对象并不是突然建立起来的,创建对象必须时必须同时创建父类以及包含于其中的对象.C++遵循如下的创建顺序: (1)如果某个类具体基类,执行基类 ...

  7. C++初始化列表各情况分析

    今天回顾了下C++初始化列表的知识,接下来我对这一知识作一总结. 我们在定义了一个类的时候,需要对类的成员进行初始化.关于初始化,有两种方法,一种在初始化列表中进行,另一种就是在构造函数中进行,对于这 ...

  8. C++中初始化列表的使用(总结)

    原文链接 https://www.cnblogs.com/dishengAndziyu/p/10906081.html 参考链接:https://www.cnblogs.com/laiqun/p/57 ...

  9. C++类构造函数初始化列表

    C++类构造函数初始化列表 构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式.例如: class CExample {public:     ...

随机推荐

  1. 使用Python进行分布式系统协调 (ZooKeeper/Consul/etcd)

    来源:naughty 链接:my.oschina.net/taogang/blog/410864 笔者之前的博文提到过,随着大数据时代的到来,分布式是解决大数据问题的一个主要手段,随着越来越多的分布式 ...

  2. superset 安装测试,基于windows 和 centos7.x

    1.刚开始在windows平台测试搭建,报各种问题,搭建可以参考官网https://superset.incubator.apache.org/installation.html#deeper-sql ...

  3. Yii 2.0 使用片段缓存

    网站首页footer中的菜单标题是从数据库读取并显示处理的. 也就是 <footer>标题里面是foreach.这样每个人打开网站就查询遍历效率会很低. <footer class= ...

  4. cogs1713 [POJ2774]很长的信息

    cogs1713 [POJ2774]很长的信息 原题链接 题解 把两串拼成A+'%'+B+'$'.跑后缀数组然后相邻两点i,i+1不在同一串里就用ht[i]更新答案. 好裸... Code // It ...

  5. 小计Tomcat的调优思路

    描述 最近在补充自己的短板,刚好整理到Tomcat调优这块,基本上面试必问,于是就花了点时间去搜集一下tomcat调优 都调了些什么,先记录一下调优手段,更多详细的原理和实现以后用到时候再来补充记录, ...

  6. 同一个电脑配置两个Git问题

    拿到公司电脑后,正常配置gitlab,以及设置邮箱等等,可以使用公司邮箱,以及一系列设置 git config --global user.name "userName" git ...

  7. 假回溯-uva140带宽

    题目链接:https://vjudge.net/problem/UVA-140 题解:这道题利用全排函数即可解决,但是这道题技巧性强,稍微不注意就会超时,一开始没有想起全排函数,自己写回溯全排超时了, ...

  8. Elastic-Job 分布式调度平台

    概述 referred:http://elasticjob.io/docs/elastic-job-lite/00-overview Elastic-Job是一个分布式调度解决方案,由两个相互独立的子 ...

  9. 剑指 Offer——和为 S 的连续正数序列

    1. 题目 2. 解答 定义两个指针,刚开始分别指向 1 和 2,求出位于这两个指针之间的元素和.如果和大于 S,前面的指针向后移直到和不大于 S 为止:反之,如果和等于 S,则此时两个指针之间的元素 ...

  10. eos TODO EOS区块链上EOSJS和scatter开发dApp

    由于我一直在深入研究EOS dApp的开发,我看了不少好文章.在这里,我汇总了下做一些研究后得到的所有知识.在本文中,我将解释如何使用EOSJS和scatter.我假设你对智能合约以及如何在EOS区块 ...