初始化列表的用法说明

类对象的构造顺序是这样的:1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员2.进入构造函数后在构造函数中执行一般计算

使用初始化列表有两个原因:

1.必须这样做:

   《C++ Primer》中提到在以下三种情况下需要使用初始化成员列表:

一、需要初始化的数据成员是对象的情况;二、需要初始化const修饰的类成员;三、需要初始化引用成员数据;

        如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。class ABC...{public:         ABC(int x,int y,int z);private:         int a;         int b;         int c;};class MyClass...{public:        MyClass():abc(1,2,3)...{}private:        ABC abc;};

        因为ABC有了显示的带参数的构造函数,那么他是无法依靠编译器生成无参构造函数的,所以没有三个int型数据,就无法创建ABC的对象。        ABC类对象是MyClass的成员,想要初始化这个对象abc,那就只能用成员初始化列表,没有其他办法将参数传递给ABC类构造函数。        另一种情况是这样的:当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。

2.效率要求这样做:       类对象的构造顺序显示,进入构造函数体后,进行的是计算,是对他们的赋值操作,显然,赋值和初始化是不同的,这样就体现出了效率差异,如果不用成员初始化类表,那么类对自己的类成员分别进行的是一次隐式的默认构造函数的调用,和一次复制操作符的调用,如果是类对象,这样做效率就得不到保障。

注意:构造函数需要初始化的数据成员,不论是否显示的出现在构造函数的成员初始化列表中,都会在该处完成初始化,并且初始化的顺序和其在声明时的顺序是一致的,与列表的先后顺序无关,所以要特别注意,保证两者顺序一致才能真正保证其效率。

为了说明清楚,假设有这样一个类:class foo{   private :    int a, b;};1、foo(){}和foo(int i = 0){}都被认为是默认构造函数,因为后者是默认参数。两者不能同时出现。2、构造函数列表的初始化方式不是按照列表的的顺序,而是按照变量声明的顺序。比如foo里面,a在b之前,那么会先构造a再构造b。所以无论 foo():a(b + 1), b(2){}还是foo():b(2),a(b+1){}都不会让a得到期望的值。如果先声明b再声明a则会更好。3、构造函数列表能够对const成员初始化。比如foo里面有一个int const c;则foo(int x) : c(x){}可以让c值赋成x。不过需要注意的是,c必须在每个构造函数(如果有多个)都有值。4、在继承里面,只有初始化列表可以构造父类的private成员。比如说class child : public foo{}foo里面的构造函数是这样写的:foo (int x) { a = x; }.而在child里面写child(int x){ foo(x); }是通过不了编译的。只有把父类初始化改为foo(int x) : a(x){}而子类构造写作child (int x) : foo(x){}才可以。

另一篇关于初始化列表的文章:

C++初始化类的成员,不但可以用构造函数(constructor)完成,而且可以用初始化类成员列表来完成。MFC大量用到此方法。例如有些初学者可能不大理解如下代码:class A{public:    int member_var; //成员变量    A();            //构造函数}A::A():member_var(0){}

他们觉得这个构造函数的定义应该只能这样写:A::A(){   member_var=1;}

其实两种方法都可。但是有些情况下,只能用第一种,而且通常情况下用第一种也会效率高些。

其实,第一种方法是真正的初始化(initialization),而在构造函数内实现的“=”操作其实是赋值(assign)。这两种方法的一切区别从这儿开始。区别大概如下:

我们知道普通变量编译器都会默认的替你初始化。他们既能初始化,也能被赋值的,而常量(const)按照其意思只能被初始化,不能赋值。否则与变量就无区别了。所以常量成员(const member)只能用成员初始化列表来完成他们的“初始化”,而不能在构造函数内为他们“赋值”。 我们知道类的对象的初始化其实就是调用他的构造函数完成,如果没有写构造函数,编译器会为你默认生成一个。如果你自定义了带参数的构造函数,那么编译器将不生成默认构造函数。这样这个类的对象的初始化必须有参数。如果这样的类的对象来做另外某个类的成员,那么为了初始化这个成员,你必须为这个类的对象的构造函数传递一个参数。同样,如果你在包含它的这个类的构造函数里用“=”,其实是为这个对象“赋值”而非“初始化”它。所以一个类里的所有构造函数都是有参数的,那么这样的类如果做为别的类的成员变量,你必须显式的初始化它,你也是只能通过成员初始化列表来完成初始化。例如: class B{......}

class A{public:B member_b;A();}A::A():B(...) //你必须显式初始化它,因为他的所有构造函数              //都是有参数的,之后才能被赋值。{B=...; //因为如上所写,已经初始化了,才能被赋值,否则错误。}

——————————————————————————————————————

初始化顺序:

class test {

       const int a;

       std:string str;

       object o;

       test():str(“df”),o(null),a(0)

{

}    

};

黄色的既是初始化列表,他们会在构造函数正式调用前被调用,且他们的初始化顺序并不是根据 初始化列表中出现的顺序,而是他们声明的顺序来初始化。如上:

初始化顺序是:a, str, o;

一般用于初始化 常量类型,静态类型的数据,或者不能独立存在的数据
时间: 2024-12-12 03:48:09

初始化列表的用法说明的相关文章

c++11之初始化列表

一.前言 C++的学习中,我想每个人都被变量定义和申明折磨过,比如我在大学笔试过的几家公司,都考察了const和变量,类型的不同排列组合,让你区别有啥不同.反正在学习C++过程中已经被折磨惯了,今天再来看看重温下那段"辉煌的历史".先来看一段代码: Player pa; // (a) Player pb(); // (b) Player pc = Player(); // (c) Player pd(Player()); // (d) pd = Player() // (e) a,b,

c++初始化列表

何谓初始化列表 与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段.在C++中,struct和class的唯一区别是默认的访问性不同,而这里我们不考虑访问性的问题,所以下面的代码都以struct来演示. struct foo { string name ; int id ; foo(string s, int i):name(s), id(i){} ; // 初始化列表 }; 构造函数的两个执行阶段 构造函数的执行

【C/C++】构造函数、默认构造函数、成员初始化列表

常见问题 Q1. 下列关于构造函数的描述中,错误的是( ) A. 构造函数可以设置默认的参数 B. 构造函数在定义类对象时自动执行 C. 构造函数可以是内联函数 D. 构造函数不可以重载 Q2. 下列代码中a.b的各个成员变量值是多少? 1 class Student 2 { 3 public: 4 Student() {} 5 void show(); 6 private: 7 string name; 8 int number; 9 int score; 10 }; 11 Student a

C++对象模型——成员初始化列表(第二章)

2.4    成员初始化列表 (Member Initialization List) 当编写一个类的构造函数时,有可能设定类成员的初始值,或者通过成员初始化列表初始化,或者在构造函数内初始化,除了四种情况,其实任何选择都差不多. 本节中,首先澄清何时使用初始化列表才有意义,然后解释初始化列表内部的真正操作是什么,然后再看一些微妙的陷阱.  下列情况中,为了让程序能够被顺利编译,必须使用成员初始化列表(不能在构造函数内初始化): 1.    当初始化一个引用的成员时 2.    当初始化一个常量

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员)、拷贝构造函数

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员).拷贝构造函数  从概念上将,可以认为构造函数分为两个阶段执行: 1)初始化阶段: 2)普通的计算阶段.计算阶段由构造函数函数体中的所有语句组成. 一.构造函数初始化列表 推荐在构造函数初始化列表中进行初始化 1.对象成员及其初始化 <span style="font-size:14px;">#include <iostream> using namespace std;

[C++11笔记001]修改通用库中的XDynamicArray,使它可以支持C++11的初始化列表和for循环

今天,有空翻了一下<C++Primer plus(第六版)>,看到里面有介绍新的for循环和初始化列表,但是我实现的动态数组XDynamicArray不支持这些新特性,没办法,只好进行改造了. 首先是for循环,如下面的样式 for(auto e:stList) { cout<<e<<endl; } 是于就各种google,和查找C++11的array的源代码,总结:就是提供一个标准的iterator和begin,end这两个方法,就可以了. 是于定义了一个iterat

C++构造函数初始化列表与赋值

C++中类的初始化操作一般有四个部分组成: 1.构造函数初始化列表 2.构造函数体内赋值 3.类外部初始化 4.类声明时直接赋值 对于内部数据类型(char,int,float...),构造函数初始化列表和构造函数体内赋值,基本上没多大区别,效率差异也不大,但两者不能共存: class Student { public: Student(char *name, int age): //A初始化列表 m_name(name), m_age(age) { } Student(char *name,

只能在初始化列表中初始化的变量

1.const变量 有几个容易混淆的地方: (1)const 的变量只能通过构造函数的初始化列表进行初始化:(貌似在c++11中可以正常编译) (2)static 的变量只能通过在类外重新定义进行初始化: (3)static const 变量 只能通过在类中直接用”=”进行赋值. 2.引用 引用只能初始化,不能赋值 3.不含默认构造函数的类的对象 因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化. 构造函数的函数体内只能做赋值而不是初始化,因此初始化const对

const成员或者引用成员必须使用构造函数初始化列表的方式

#include<iostream.h> class A { const int a; int b; }; void main() { A obja; }编译出现如下错误:error C2512: 'A' : no appropriate default constructor available;如果将const去掉就没错了! #include<iostream.h> class A { public: const int a; int b; A(int x):a(x){} };