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. STM32的备份寄存器测试

    1. 研究STM3的备份寄存器,注意,如果要测试这个例程的话,VBAT不能和VDD接一起,必须分开. 2. 理解,备份寄存器可以有VBAT独立供电,也就是外接电池,备份寄存器在VBAT供电情况下,如果 ...

  2. L016-linux系统文件权限体系实战深入讲解小节

    L016-linux系统文件权限体系实战深入讲解小节 不知道今天能不能写完哈,能写完发出来就是这周发两次小结了,有进步哦,不过L015和L016两节课内容也确实不多,进入正题 上一课学到了chmod. ...

  3. 【Unity3d】MenuItem修饰的方法无法触发的可能原因

    遇到了MenuItem修饰的方法无法触发的情况,顺利解决. 类放在Editor目录下,该类下其他方法被MenuItem修饰可以触发. 后来发现我修饰的方法和该类下另一个方法重名了. 改方法名,问题解决 ...

  4. MyBatis.Net 配置

    假设我们现在有这样的需求,要对学生信息进行管理 学生表有要以下要求 字段名称 数据类型 说明 stuNo 字符 学号,该列必填,为主键递增 stuName 字符 学生姓名,该列必填,要考虑姓氏可能是两 ...

  5. Django之视图系统

    Django的View(视图) 一个视图函数(类),简称视图,是一个简单的python函数(类),它接受web请求并返回web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,或者 ...

  6. ADO.Net之SqlConnection、 Sqlcommand的应用

    ADO.Net之SqlConnection. Sqlcommand的应用 SqlConnection 的介绍与应用 1.介绍与作用 SqlConnection是ADO.NET中的连接类. 使用sqlc ...

  7. CentOS7使用阿里源安装最新版Docker

    卸载已经安装的Docker sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker ...

  8. C++进阶训练——停车收费系统设计

    一.简介 经过一段时间的c++基础学习,是时候做一个较为全面的.运用c++功能的较复杂的项目练练手了. 运用软件:Visual Studio   (VS). 题目:c++停车收费系统设计(某本编程书进 ...

  9. 为phpStorm 配置PHP_CodeSniffer自动检查代码

    通过composer 安装PHP_CodeSniffer : squizlabs/PHP_CodeSniffer gihub地址 composer global require "squiz ...

  10. Phonegap 环境配置

    目前要开发 Web App 还是有比较多的选择的 如 Phonegap.MUI.AppCan,接下来以 Web前端开发工程师 的角度来一个 Phonegap 的 First Blood 一.开发环境: ...