class Circle

{

public:

Circle(float r);

private:

float radius;

};

Circle::Circle(float r) { radius = r }

通常都是这么写的。还有一种写法,类名::类名(形参表):内嵌对象1(形参表),内嵌对象2(形参表)... { 类的初始化 }。使用初始化列表比使用赋值语句的效率要高。

上面的构造函数可以写成如下形式:

Circle::Circle(float r):radius(r){}

为什么使用初始化列表比使用赋值语句效率高呢?

1:初始化列表”来初始化成员变量,进行的是初始化工作,调用的是构造函数,只需要调用一次拷贝构造函数;

2:在构造函数里面直接赋值,进行的是赋值操作,调用的是assignment函数,在调用assignment函数之前,还必需调用一次默认构造函数;

3:有些时候必须用到初始化列表,而不能在构造函数里直接赋值,比如引用成员和const成员,因为它们都不能被赋值,而只可以被初始化;

Effective C++笔记—构造函数赋值VS初始化列表

http://blog.csdn.net/lifeisbetter/article/details/5099085

条款12: 尽量使用初始化而不要在构造函数里赋值

条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同

在写构造函数时,必须将参数值传给相应的数据成员。有两种方法来实现。

第一种方法是使用成员初始化列表:

第二种方法是在构造函数体内赋值:

两种方法有重大的不同。

从纯实际应用的角度来看,有些情况下必须用初始化。特别是类成员有const(因为const成员只能被初始化,不能被赋值)和引用数据成员只能用初始化,不能被赋值。

对象的创建分两步:

1. 数据成员初始化。(参见条款13)

2. 执行被调用构造函数体内的动作。

01.template<class t>

02.class namedptr {

03.public:

04.  namedptr(const string& initname, t *initptr);

05.  ...

06.

07.private:

08.  const string name;

09.  t * const ptr;

10.};

如果没有为name指定初始化参数,string的缺省构造函数会被调用。当在namedptr的构造函数里对name执行赋值时,会对name调用operator=函数。这样总共有两次对string的成员函数的调用:一次是缺省构造函数,另一次是赋值。

相反,如果用一个成员初始化列表来指定name必须用initname来初始化,name就会通过拷贝构造函数以仅一个函数调用的代价被初始化。

换句话说,通过成员初始化列表来进行初始化总是合法的,效率也决不低于在构造函数体内赋值,它只会更高效。另外,它简化了对类的维护(见条款m32),因为如果一个数据成员以后被修改成了必须使用成员初始化列表的某种数据类型,那么,什么也不用变。

但有一种情况下,对类的数据成员用赋值比用初始化更合理。这就是当有大量的固定类型的数据成员要在每个构造函数里以相同的方式初始化的时候。这时应该将成员初始化列表用一个对普通的初始化函数的调用来代替。

例1 必须使用

设想你有一个类成员,它本身是一个类或者结构,而且只有一个带一个参数的构造函数。

class CMember {

public:

CMember(int x) { ... }

};

因为Cmember有一个显式声明的构造函数,编译器不产生一个缺省构造函数(不带参数),所以没有一个整数就无法创建Cmember的一个实例。

CMember* pm = new CMember;        // Error!!

CMember* pm = new CMember(2);     // OK

如果Cmember是另一个类的成员,你怎样初始化它呢?你必须使用成员初始化列表。

class CMyClass {

CMember m_member;

public:

CMyClass();

};

//必须使用成员初始化列表

CMyClass::CMyClass() : m_member(2)

{

???

}

没有其它办法将参数传递给m_member,如果成员是一个常量对象或者引用也是一样。根据C++的规则,常量对象和引用不能被赋值,它们只能被初始化。

例2 效率

当成员类具有一个缺省的构造函数和一个赋值操作符时。MFC的Cstring提供了一个完美的例子。假定你有一个类CmyClass具有一个Cstring类型的成员m_str,你想把它初始化为"yada yada."。你有两种选择:

CMyClass::CMyClass() {

// 使用赋值操作符

// CString::operator=(LPCTSTR);

m_str = _T("yada yada");

}

//使用类成员列表

// and constructor CString::CString(LPCTSTR)

CMyClass::CMyClass() : m_str(_T("yada yada"))

{

}

在它们之间有什么不同吗?是的。编译器总是确保所有成员对象在构造函数体执行之前初始化,因此在第一个例子中编译的代码将调用CString::Cstring来初始化m_str,这在控制到达赋值语句前完成。在第二个例子中编译器产生一个对CString:: CString(LPCTSTR)的调用并将"yada yada"传递给这个函数。结果是在第一个例子中调用了两个Cstring函数(构造函数和赋值操作符),而在第二个例子中只调用了一个函数。在Cstring的例子里这是无所谓的,因为缺省构造函数是内联的,Cstring只是在需要时为字符串分配内存(即,当你实际赋值时)。但是,一般而言,重复的函数调用是浪费资源的,尤其是当构造函数和赋值操作符分配内存的时候。在一些大的类里面,你可能拥有一个构造函数和一个赋值操作符都要调用同一个负责分配大量内存空间的Init函数。在这种情况下,你必须使用初始化列表,以避免不要的分配两次内存。在内部类型如ints或者longs或者其它没有构造函数的类型下,在初始化列表和在构造函数体内赋值这两种方法没有性能上的差别。不管用那一种方法,都只会有一次赋值发生。

例3 顺序

关于C++初始化类成员,它们是按照声明的顺序初始化的,而不是按照出现在初始化列表中的顺序。

class CMyClass {

CMyClass(int x, int y);

int m_x;

int m_y;

};

CMyClass::CMyClass(int i) : m_y(i), m_x(m_y)

{

}

你可能以为上面的代码将会首先做m_y=I,然后做m_x=m_y,最后它们有相同的值。但是编译器先初始化m_x,然后是m_y,,因为它们是按这样的顺序声明的。结果是m_x将有一个不可预测的值。有两种方法避免它,一个是总是按照你希望它们被初始化的顺序声明成员,第二个是,如果你决定使用初始化列表,总是按照它们声明的顺序罗列这些成员。

C++中构造函数的写法的更多相关文章

  1. (转载)C++中, 构造函数和析构函数能不能被显示调用?

    (转载)http://blog.csdn.net/zhangxinrun/article/details/6056321 代码: view plaincopy to clipboardprint?#i ...

  2. 【校招面试 之 C/C++】第5题 C++各种构造函数的写法

    构造函数 ,是一种特殊的方法 .主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 .特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数 ...

  3. 显示调用C++中构造函数和析构函数(有什么弊端)

    1.C++中, 构造函数和析构函数可以被显示调用. 显示调用默认构造函数的语法: a.A::A();(不能写成a.A();) , 显示调用非默认构造函数的语法: a.A::A(7);(不能写成a.A( ...

  4. C#中构造函数的作用

    C#中构造函数的作用 共同点: 都是实例化对象,初始化数据的 默认构造是说所有的类都从祖先object那继承了空参的构造方法,你不写与写空参构造都存在,而有参数的构造一般是自己写的,写就有不写就没有, ...

  5. 深入理解Javascript中构造函数和原型对象的区别

    在 Javascript中prototype属性的详解 这篇文章中,详细介绍了构造函数的缺点以及原型(prototype),原型链(prototype chain),构造函数(constructor) ...

  6. C++C++中构造函数与析构函数的调用顺序

    http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2 ...

  7. javaweb开发过程中的地址写法

    凡是要表示web资源的地址,比如浏览器地址栏中,都是 /凡是要表示硬盘地址, 都是 \  public class ServletDemo1 extends HttpServlet { //实际开发过 ...

  8. SpringMVC,MyBatis项目中兼容Oracle和MySql的解决方案及其项目环境搭建配置、web项目中的单元测试写法、HttpClient调用post请求等案例

     要搭建的项目的项目结构如下(使用的框架为:Spring.SpingMVC.MyBatis): 2.pom.xml中的配置如下(注意,本工程分为几个小的子工程,另外两个工程最终是jar包): 其中 ...

  9. Oracle存储过程中跳出循环的写法

    注:本文来源于: <  Oracle存储过程中跳出循环的写法   > Oracle存储过程中跳出循环的写法 记录exit和return的用法 1:exit用来跳出循环 loop IF V_ ...

随机推荐

  1. 一些奇怪的Javascript用法

    阅读AngularJS时,看到一些奇怪的Javascript用法.1.(function(){        a.work=function(){}   })(a)   声明一个匿名函数并执行 2. ...

  2. Learning Python 011 高级特性 1

    Python 高级特性 1 切片 将L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']列表中前上个3个元素: L = ['Michael', 'Sarah ...

  3. 人工智能: 自动寻路算法实现(三、A*算法)

    博客转载自:https://blog.csdn.net/kwame211/article/details/78139506 本篇文章是机器人自动寻路算法实现的第三章.我们要讨论的是一个在一个M×N的格 ...

  4. 文件格式——fastq格式

    fastQ格式 FASTQ是一种存储了生物序列(通常是核酸序列)以及相应的质量评价的文本格式. 他们都是以ASCII编码的.现在几乎是高通量测序的标准格式.NCBI Short Read Archiv ...

  5. 1.如何绕过WAF(Web应用防火墙)

    一:大小写转换法: 看字面就知道是什么意思了,就是把大写的小写,小写的大写.比如: SQL:sEleCt vERsIoN(); ‍‍XSS:)</script> 出现原因:在waf里,使用 ...

  6. HTML5 & CSS3编程入门经典 ((美)Rob Larsen) pdf扫描版

    HTML和CSS是构建网页所需要了解的两种核心编程语言,拉尔森编著的这本<HTML5&CSS3编程入门经典>详细介绍了这两种语言. <HTML5&CSS3编程入门经典 ...

  7. OpenStack基础知识-tox的详解介绍

    1.tox简介 tox是通用的虚拟环境管理和测试命令行工具.tox能够让我们在同一个Host上自定义出多套相互独立且隔离的python环境,每套虚拟环境中可能使用了不同的 Python 拦截器/环境变 ...

  8. 2017乌鲁木齐区域赛I(带权并查集)

    #include<bits/stdc++.h>using namespace std;int f[200010];//代表元long long rl[200010];//记rl[i]为结点 ...

  9. AtCoder Beginner Contest 115 题解

    题目链接:https://abc115.contest.atcoder.jp/ A Christmas Eve Eve Eve 题目: Time limit : 2sec / Memory limit ...

  10. [USACO07DEC]观光奶牛Sightseeing Cows 二分答案+判断负环

    题目描述 Farmer John has decided to reward his cows for their hard work by taking them on a tour of the ...