C++ 初始化列表(Initialization List)

initialization,list · 浏览次数 : 3

小编点评

**CPoint** ```cpp class CPoint { public: CPoint(float x = 0.0) : _x(x){} float x() {return _x;} void x(float xval){_x=xval;} protected: float _x; }; ``` **CPoint2d** ```cpp class CPoint2d : public CPoint { public: CPoint2d(float x = 0.0,float y=0.0) : CPoint(x),_y(y){} float y(){return _y;} void y(float yval){_y=yval;} protected: float _y; }; ``` **CPoint3d** ```cpp class CPoint3d : public CPoint2d { public: CPoint3d(float x = 0.0, float y = 0.0,float z = 0.0) : CPoint2d(x,y),_z(z){} float z(){return _z;} void z(float zval){_z=zval;} protected: float _z; }; ``` **关于initialization list** **initlization list**是指在构造器调用后执行的代码。它是在构造器主体动作之前执行的代码。 **在CPoint3d构造器中没有列出initialization list,因为**CPoint3d**类只拥有了一个构造器,且该构造器没有参数。 **编译器的插码结果** ``` &CPoint3d::CPoint3d( float x = 0.0, float y = 0.0, float z = 0.0 ) { _z = z; } 3 m_data1(m_data2); // 此时 m_data2 还没有初值,糟糕4 m_data2(val);5 } ``` 在这个例子中,`_z`变量的初始化被委托给了`m_data2`。由于`m_data2`在构造器中尚未初始化,导致编译器报错。

正文

  请注意以下继承体系中各class的constructors写法:

 1 class CPoint
 2 {
 3 public:
 4     CPoint(float x=0.0)
 5     :_x(x){}
 6     
 7     float x() {return _x;}
 8     void x(float xval){_x=xval;}
 9 protected:
10     float _x;
11 };
12 
13 class CPoint2d:public CPoint{
14 
15 public:
16     CPoint2d(float x=0.0,float y=0.0)
17     :CPoint(x),_y(y){}
18 
19    float y(){return _y;}
20    void y(float yval){_y=yval;}
21 protected:
22     float _y;
23 };
24 
25 class CPoint3d:public CPoint2d{
26 public:
27     CPoint3d(float x=0.0,float y=0.0,float z=0.0)
28      :CPoint2d(x,y),_z(z){}
29      
30     float z(){return _z;}
31     void z(float zval){_z=zval;}
32 
33 protected:
34     float _z;
35 
36 
37 };

  在constructor声明之后有一个:符号,后面紧跟着一个(以上)的函数调用动作,这一行就是所谓的initialization list。它的作用是在进入constructor主体动作之前,,先唤起其中所列的函数。例如上面的:

  第5行表示:在执行CPoint::CPoint(x)之前,先执行_x(x); (注:语言内建类型如int、float、long等等也是一种class,因为变量_x的类型是float,所以_x(x)的意思是启动“float class”的constrnctor,也就把_x的初值设为x;

  第17行表示:执行CPoint2d::CPoint2d(x,y)之前,先执行CPoint(x)和_y(y).

  第28行表示:执行CPoint3d::CPoint3d(x,y,z)之前,先执行CPoint2d(x,y)和_z(z).

  因此当我产生一个CPoint3d object如下:

CPoint3d aPoint3d(1.1, 2.2, 3.3);

  会有以下六个动作依序被调用:

_x(1.1); // 相当于 _x = 1.1;
CPoint::CPoint(1.1); // 本例沒做什么事
_y(2.2); // 相当于 _y = 2.2;
CPoint2d::CPoint2d(1.1, 2.2); // 本例沒做什么事
_z(3.3); // 相当于_z = 3.3;
CPoint3d::CPoint3d(1.1, 2.2, 3.3); // 本例沒做什么事

  你可能会问,既然继承体系中的建构方式是由内而外,由上而下,那么这里产生个CPoint3d object,必然会调用CPoint2d和CPoint的constrnctor,而所有初始化动作都可以在其中完成,initialization list的出现会不会是显得多此一举?做个测试就知道了,把上一段27行的代码改为这样试试:

CPoint3d( float x = 0.0, float y = 0.0, float z = 0.0 ) { _z = z; }

  其中没有指定initialzation list。结果竟然无法通过编译:

error C2668: 'CPoint2d::CPoint2d' : ambiguous call to overloaded
function

  也就是说,当编译器根据继承体系往上一层调用base class constructor时,发现CPoint2d有两个constructors,而它不知道应该调用哪一个。这就是initialization list最明显的存在的价值。如果本例的CPoint2d只有一个constructor,像这样:

1 class CPoint2d : public CPoint {
2 public:
3   CPoint2d( ) { _y = 0.0; } // default constructor
4 protected:
5   float _y;
6 };

  或者这样

1 class CPoint2d : public CPoint {
2 public:
3     CPoint2d( float x = 0.0, float y = 0.0 )
4     : CPoint( x ), _y( y ) { }
5 protected:
6     float _y;
7 };

  而 CPoint3d constructor 中沒有列出 initialization list,像这样:

1 class CPoint3d : public CPoint2d {
2 public:
3     CPoint3d( float x = 0.0, float y = 0.0, float z = 0.0 ) { _z = z; }
4 protected:
5     float _z;
6 };

  那么并不会出现前面的编译错误。

  以上的讨论是针对base class的建构,同理对于member class 也是一样。如果member calss有一个以上的constructors,那么内含embedded object的那个class就必须在其constructor中指定initialization list,否则一样会出现编译错误。

  initialization list到底会在编译器底层发生什么影响呢?编译器会以“适当的次序”将initialization list中指定的member调用动作安插到constructor之内,并置于任何user code之前,下面这张图可以表现出编译器的插码结果:

 

   有一些微妙的地方必须注意,编译器安插在constructor中的members声明动作是以members在class中的声明次序为根据,而不是以initializtion list中的排序为根据。如果两者在外观上错乱,很容易引起程序设计时的一些困扰或失误。例如:

class X {
public:
    X(int val) : m_data2(val), m_data1(m_data2) { }
protected:
    int m_data1;
    int m_data2;
};

  我们很容易误以为在X constructor中是以val 设定m_data2,再将m_data2设定给m_data1.但根据两个data members的声明顺序,实际发生的动作却是:

1 X::X(int val)
2 {
3     m_data1(m_data2); // 此时 m_data2 还没有初值,糟糕
4     m_data2(val);
5 }

  于是,当我们产生一个X object:

X x(3);

  其实data members的内容可能成为这样:

x.m_data1 = -2124198216 // 这不是我们希望的
x.m_data2 = 3

一个比较好的做法是,把class X重新设计如下:

1 class X {
2 public:
3     X(int val) : m_data2(val) { m_data1 = m_data2; }
4 protected:
5     int m_data1;
6     int m_data2;
7 };

 

与C++ 初始化列表(Initialization List)相似的内容:

C++ 初始化列表(Initialization List)

请注意以下继承体系中各class的constructors写法: 1 class CPoint 2 { 3 public: 4 CPoint(float x=0.0) 5 :_x(x){} 6 7 float x() {return _x;} 8 void x(float xval){_x=xval

初识Redis与桌面客户端

Redis介绍 什么是Redis Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。 Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:字符串、列表、

[转帖]流程控制之for循环

https://www.cnblogs.com/caodan01/p/14949052.html 目录 一 语法 二 案例 一 语法 # 》Shell风格语法 for 变量名 [ in 取值列表 ] do 循环体 done # 》C语言风格语法 for ((初值;条件;步长)) do 循环体 don

初始化使用花括号还是圆括号?

C++11引入了使用{}来初始化对象,这样初始化一个对象有如下几种方法: class MyClass { public: int value; MyClass(int _val):value(_val){} }; int main() { MyClass cls1(1); MyClass cls2{

Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别

有个需要是需要在安装包安装初始化时安装 Microsoft Visual c++ 2013 Redistributable 也就是判断软件安装前需不需要运行 `vcredist_x64.exe` 和 `VC_redist.x64.exe` 这两个程序 第一反应就是可以通过注册表判断是否已经安装过环境

万字长文总结与剖析C语言关键字 -- <>

C总结与剖析:关键字篇 -- <> 目录C总结与剖析:关键字篇 -- <>程序的本质:二进制文件变量1.变量:内存上的某个位置开辟的空间2.变量的初始化3.为什么要有变量4.局部变量与全局变量5.变量的大小由类型决定6.任何一个变量,内存赋值都是从低地址开始往高地

C# readonly修饰符

readonly修饰符在作祟 强化官方解释: 1. readonly是一个修饰字段的关键字:被它修饰的字段只有在初始化或者构造函数中才能够赋值. 2. readonly修饰的引用类型字段必须始终引用同一对象: readonly 修饰符可防止字段替换为引用类型的其他实例, 但是,readonly不会妨

FreeRTOS简单内核实现2 双向链表

FreeRTOS 的 list.c / list.h 文件中有 3 个数据结构、2 个初始化函数、2 个插入函数、1 个移除函数和一些宏函数,链表是 FreeRTOS 中的重要数据结构

后端服务之应用预热

一 背景 C端服务应用升级和重启,导致耗时瞬时抖动,业务超时,应用监控报警,上游感知明显,导致用户体验变差。 二 应用升级重启导致抖动的原因 1 C端服务应用升级和重启的冷启动阶段,它需要重新加载和初始化各种资源,例如数据库连接、缓存数据等,导致耗时瞬时飙升。 2 应用重启后,本地缓存失效,应用需要

WinDBG详解进程初始化dll是如何加载的

一:背景 1.讲故事 有朋友咨询个问题,他每次在调试 WinDbg 的时候,进程初始化断点之前都会有一些 dll 加载到进程中,比如下面这样: Microsoft (R) Windows Debugger Version 10.0.25200.1003 X86 Copyright (c) Micro