条款01:视C++为一个语言联绑

C++的四个语言层次:

  1. C:C++是以C为基础的。基本数据类型、语句、预处理器、数组、指针等统统来自C。
  2. Oject-Oriented C++:面向对象这一特性包含了:类,封装(声明与实现相分离),继承(多继承和多重继承、构造函数、析构函数、拷贝构造函数、拷贝赋值运算符),多态(静态绑定:函数重载,动态绑定:虚函数),虚函数等
  3. Template C++:C++的泛型编程能力。
  4. STL:一个标准的template库,里面介绍了容器、迭代器、算法以及函数对象等模板类和模板函数。

综述:C++并不是一个带有一组守则的一体语言:它是从四个次语言组成的联绑政府,每个次语言都有自己的规约。

条款02:尽量以const,enum,inline替换#define

条款02:尽量以const,enum,inline替换#define

  对于单纯常量,最好以const对象或enums替换#define。

  对于形似函数的宏,最好改用inline函数替换#define

条款03:尽可能使用const

  STL的迭代器是以指针为根据塑模出来,所以迭代器的作用就像个T*的指针。声明迭代器为const就像声明指针为const一样(即声明一个T*const指针),表示这个迭代器不得指向不同的东西,但它所指的东西的值是可以改动的。如果希望迭代器所指的东西是不可被改动的,需要的是const_iterator。

 
vector<int> vec;
const vector<int>::iterator = vec.begin();
*iter = 10; // 没问题,改变iter所指物
++iter; // 错误!iter是const
vector<int>::const_iterator cIter = vec.begin();
*cIter = 10; // 错误!*cIter是const
++cIter; // 没问题,改变cIter

请记住

  • 将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用哉内的对象、函数参数、函数返回类型、成员函数本体。
  • 编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”。
  • 当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可以避免代码重复。

条款04:确定对象被使用前已先被初始化

  类的构造函数的次序是先执行构造函数初始化列表,初始化所有成员变量,然后再执行构造函数体,构造函数体内的成员赋值已经不属于初始化的范畴,成员都是用拷贝赋值。

  如果类没有初始化列表,则类会先执行默认构造函数,构造出所有成员变量后,再执行函数体内的拷贝赋值。

  C++类的成员初始化是有着明显的次序的,一般是基类的成员先初始化,然后派生类的成员按定义的顺序初始化。所以类的构造函数初始化列表上的初始化顺序跟类真实的成员初始化顺序是没有关系的。

“不同编译单元内定义之non-local static对象”

  static对象,其寿命从被构造出来直到程序结束为止。

  函数内的static对象称为local static对象(因为它们对函数而言是local),其他static对象称为non-local static对象。程序结束时static对象会被自动销毁,也就是它们的析构函数会在main()结束时被自动调用。

  当我们的某个编译单元内的某个non-local static对象的初始化动作使用了另一编译单元的某个non-local static对象,它所用到的这个对象可以尚未被初始化。C++关于定义于不同编译单元内的non-local static对象的初始化次序并无明确定义。

比如在a.cpp里我们定义一个类,一个该类的对象

 
class FileSystem
{
public:
size_t numDisks()const;
};
extern FileSystem tfs;

现在同一个项目下的b.cpp文件中有一个类,类构造函数用到了tfs对象。

 
class Directory
{
public:
Directory(params);
};
Directory::Directory(params)
{
size_t disks = tfs.numDisks();
}

现在如果我们创建了一个Directory对象

Directory tempDir(params);

上面的代码就可能会出问题,除非能保证tfs在tempDir之前先初始化,否则tempDir的构造函数会用到尚未初始化的tfs。

解决方案:

C++保证,函数内的local static对象会在该函数被调用期间,首次遇到该对象的定义的时候被初始化。

  所以如我们把tfs和tempDir设计为一个函数,函数返回该类的一个static对象引用就可以解决问题了。

  所以我们可以改写上面的代码:

 
FileSystem& tfs()
{
static FileSystem fs;
return fs;
} Directory& tempDir()
{
static Directory td;
return td;
}

请记住

  • 为内置型对象进行手工初始化,因为C++不保证初始化它们。
  • 构造函数最好使用成员初始化列表,而不要在函数体内使用赋值操作。初始列表列出的成员变量,其排列次序应该和它们在class中的声明次序相同。
  • 为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象。

【Effective C++】让自己习惯C++的更多相关文章

  1. Effective C++ ——让自己习惯C++

    条款一:视C++为一个语言联邦 为了理解C++,你必须认识其主要的次语言.幸运的是总共只有四个: C:C++是由C语言继承而来的,必然对C有很好的兼容性,这一部分主要包括C中的一些语言,库函数等.但当 ...

  2. Effective C++ —— 让自己习惯C++(一)

    条款01 : 视C++为一个语言联邦 C++ == C(C基本语法) + Object-Oriented C++(类,封装,继承,多态……) + Template C++(泛型编程) + STL(容器 ...

  3. Effective C++ —— 构造/析构/赋值运算(二)

    条款05 : 了解C++默默编写并调用哪些函数 编译器可以暗自为class创建default构造函数.copy构造函数.copy assignment操作符,以及析构函数. 1. default构造函 ...

  4. C++易混淆知识点整理

    // 1 /////////////////////////////////////////////////////////////////////// // 常量指针:,指针可修改,变量不可修改(只 ...

  5. #pragma init_seg

    先进后出原则,最先初始化的最后析构! 1.C++中全局对象.变量的构造函数调用顺序是跟声明有一定关系的,即在同一个文件中先声明的先调用.对于不同文件中的全局对象.变量,它们的构造函数调用顺序是未定义的 ...

  6. [.NET] 《Effective C#》快速笔记(一)- C# 语言习惯

    <Effective C#>快速笔记(一)- C# 语言习惯 目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 ...

  7. 《Effective C#》快速笔记(一)- C# 语言习惯

    目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 is 或 as 操作符而不是强制类型转换 四.使用 Conditional ...

  8. 《Effective C++》第1章 让自己习惯C++-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  9. Effective C++(第三版)笔记 ---- 第一部分让自己习惯C++

    内容从侯捷译版的<Effective C++>(第三版)摘录 条款一 C++作为一个多种范式融合的语言,可以看成是语言的联邦,它包含了一下四种主要的次语言: C.C++以C为基础,很多时候 ...

  10. seven habits of highly effective people 高效能人士的七个习惯

    习惯的模型 : dependent 依赖  -- independent 独立自主 --interdependent  互相依赖 1: be  proactive 主动积极 what you can ...

随机推荐

  1. CodeForces 380.C Sereja and Brackets

    题意 一串括号序列,只由(和)组成,然后是m个提问,提问l和r区间内,最大的匹配匹配括号数. 思路 第一,贪心的思想,用最正常的方式去尽量匹配,详细点说就是,先找到所有的(),然后删除这些(),再找所 ...

  2. LeetCode OJ——Pascal's Triangle II

    http://oj.leetcode.com/problems/pascals-triangle-ii/ 杨辉三角2,比杨辉三角要求的空间上限制Could you optimize your algo ...

  3. 扩展欧几里得算法(exGCD)学习笔记

    @(学习笔记)[扩展欧几里得] 本以为自己学过一次的知识不会那么容易忘记, 但事实证明, 两个星期后的我就已经不会做扩展欧几里得了...所以还是写一下学习笔记吧 问题概述 求解: \[ax + by ...

  4. SpringUtils写法

    @Componentpublic class SpringUtils implements ApplicationContextAware { @Override public void setApp ...

  5. DevExpress的GridControl如何实现打印和打印预览 z

    第一种方法:             System.Drawing.Printing.PageSettings set_print_page = new System.Drawing.Printing ...

  6. Hibernate操作Blob数据

      首先看数据库.数据库中新建一个BlobTable表,表中有两个字段,一个id(主键)一个picture字段是Blob类型字段.然后使用Hibernate向该数据库中写入和读取数据 在POJO类中p ...

  7. 学会用core dump调试程序错误

    最来在项目中遇到大型程序出现SIGSEGV ,一直不知道用core dump工具来调试程序,花了近一周的时间,才定位问题,老大很生气,后果很严重,呵呵,事后仔细学习了这块的知识,了解一点core du ...

  8. serialVersionUID的作用以及如何用idea自动生成实体类的serialVersionUID

    转载:http://blog.csdn.net/liuzongl2012/article/details/45168585 serialVersionUID的作用: 通过判断实体类的serialVer ...

  9. Linux C高级编程——网络编程基础(1)

    Linux高级编程--BSD socket的网络编程 宗旨:技术的学习是有限的,分享的精神是无限的. 一网络通信基础 TCP/IP协议簇基础:之所以称TCP/IP是一个协议簇,是由于TCP/IP包括T ...

  10. ubuntu下调试ffmpeg程序出现undefined reference to pthread_once ,undefined reference to uncompress错误

    Ubuntu(版本16.04)下默认配置编译Ffmpeg(版本4.1.3configure 添加选项--enable-threads),将编译好的ffmpeg库添加到程序 中进行编译出现undefin ...