首页 > 编程语言 >C++ 初始化列表(Initialization List)

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

时间:2024-05-16 22:29:56浏览次数:12  
标签:CPoint2d Initialization float List C++ public CPoint3d 0.0 class

  请注意以下继承体系中各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 };

 

标签:CPoint2d,Initialization,float,List,C++,public,CPoint3d,0.0,class
From: https://www.cnblogs.com/ruanchunyi/p/18196886

相关文章

  • 关于“error: Microsoft Visual C++ 14.0 is required. Get it with "Build Tools for
    安装库之前一定要注意python版本,今天鬼迷日眼的装一堆堆库,一个回车冒出来这个鬼问题。百度无果后灵光乍现,只安装报错时对应的库:condainstallnumpy==1.20.1结果在输出里找出这一段:Specifications:-numpy==1.20.1->python[version='>=3.7,<3.8.0a0|>=3.8,<3.9.0a0|>=......
  • P2 C++ 编程范式
    章节链接代码链接目录2.1.1C++工程的一般组织结构2.1.2C++工程在机器人中的组织结构2.2C++代码的编译2.2.1g++编译2.2.2make编译✅2.2.3CMake编译2.1.1C++工程的一般组织结构一般情况下,C++工程的组织结构是将不同的功能封装在不同的类中,每个类用配套的头文件......
  • 从C到C++
    const关键字用法(1)定义常量#include<iostream>usingnamespacestd;intmain(){ constintMAX_VAL=23; constdoublePi=3.14; constchar*SHOOL_NAME="SDWU"; return0;}(2)定义常量指针不可以通过常量指针修改指向的内容.#include<iostream>usingnam......
  • C++_交叉编译和pybind11
    编译本地编译和交叉编译本地编译当前平台编译交叉编译交叉编译是指在一个平台上编译另一个平台上运行的代码。在C++中,交叉编译通常涉及以下步骤:安装交叉编译工具链。配置编译环境。使用工具链编译代码。首先,确保安装了交叉编译工具链,例如gcc-arm-l......
  • C++模板编程-enable_if
    std::enable_if的使用对于重载的函数或者函数模板的选择上,编译器内部有一个自己的规则,并不是简单粗暴的对函数就优先选择,对函数模板就靠后选择替换失败并不是一个错误(SFINAE):SubstitutionFailureIsNotAnError,SFINAE看成是C++语言的一种特性或者说一种模板设计中要遵循的......
  • openGauss curosr-executemany_query-vars_list
    curosr.executemany(query,vars_list)功能描述此方法执行SQL命令所有参数序列或序列中的SQL映射。原型curosr.executemany(query,vars_list)参数表1curosr.executemany参数关键字参数说明query待执行的SQL语句。vars_list变量列表,匹配query中%s占位符。......
  • openGauss cursor-execute-query-vars_list
    cursor.execute(query,vars_list)功能描述此方法执行被参数化的SQL语句(即占位符,而不是SQL文字)。psycopg2模块支持用%s标志的占位符。原型curosr.execute(query,vars_list)参数表1curosr.execute参数关键字参数说明query待执行的sql语句。vars_list变量列......
  • 深度解读《深度探索C++对象模型》之C++虚函数实现分析(三)
    “深度解读《深度探索C++对象模型》”系列已经在CSDN上和我的公众号上更新完毕,请有需要的同学移步到我的CSDN主页里去阅读,主页地址:https://blog.csdn.net/iShare_Carlos?spm=1010.2135.3001.5421或者敬请关注我的公众号:iShare爱分享前面两篇请从这里阅读:深度解读《深度探索C+......
  • LeetCode 1669. Merge In Between Linked Lists
    原题链接在这里:https://leetcode.com/problems/merge-in-between-linked-lists/description/题目:Youaregiventwolinkedlists: list1 and list2 ofsizes n and m respectively.Remove list1'snodesfromthe ath nodetothe bth node,andput list2 in......
  • 《Effective C++》第三版-5. 实现(Implementations)
    目录条款26:尽可能延后变量定义式的出现时间(Postponevariabledefinitionsaslongaspossible)条款27:尽量少做转型动作(Minimizecasting)条款28:避免返回handles指向对象内部成分(Avoidreturning“handles”toobjectinternals)条款29:为“异常安全”而努力是值得的(Striveforexc......