我根据自己的理解,对原文的精华部分进行了提炼,并在一些难以理解的地方加上了自己的“可能比较准确”的「翻译」。

Chapter 1 让自己习惯C++

条款 1 :视 C++为一个语言联邦 (P41 )

c++其实可以视为有四个部分:

  1. C (C++实际上以C为基础)
  2. Object-Oriented C++ (C++面向对象)
  3. Template C++ (C++泛型编程)
  4. STL (template程序库)

条款 2:尽量以 const ,enum , inline 替换 #define ( P43 )

标题可翻译为“宁可以编译器替换预处理器”

首先我们强调#define有时会带来很多麻烦。

当你做出这样的事情: #define VAR 1.653

记号名称VAR或许从未被编译器看见,或许在编译期开始处理源码之前它就被预处理器移走了。于是VAR记号可能没有进入记号表(symbol table)内。重点来了,当你运用此「常量」但是却获得了一个编译错误信息,可能会有这样的困惑:这个错误信息也许仅提及VAR的值1.63而没有关于“VAR”的任何提示。一旦这个VAR宏被定义在一个你不知道的头文件内,你将对“1.63是哪来的”毫无概念,于是会为追踪它而浪费时间。

解决之道是以一个真正的常量替换上述的宏(#define)

const double Var = 1.63; //习惯上const变量名开头字母大写

作为语言常量,Var肯定会被编译器看到,从而进入记号表内。

考虑常量时,有一种情况值得提一下。

常量指针(const pointers)

常量定义式通常放在头文件内(以便被不同源码用到),因此有必要将指针声明为const:

注意,我们平常说的 const xx* = xx 是指xx*指针不能对所指物xx进行变动。而这里所说的“将指针声明为const”是指此指针本身的地址值不能有变动

例如在header里定义一个常量char*字符串,必须写“const”两次:

const char* const authorName = "Shit"; //后面的条款会提到为啥这么写

Specially: class里的常量很多时候声明为static const xxx (至多有一份实体) 然而这只是个声明

对于class专属static常量,只有声明而没有定义式,要想取此常量地址的话,则必须有定义式,可以这么做:

假设你是在头文件的class Num里定义了静态常量static const int Num = 5,则可以在实现文件中提供此常量的定义:

const int Num::Num; 因为在头文件定声明时已经赋了初值,所以定义时不用赋值

值得注意的是,有些编译器不支持声明期间赋值,你可以在定义式中赋初值 (事实上,比较鼓励这种做法)

如果你的编译器不允许声明期间赋初值,而class里又有声明数组大小这种操作,那么可以用enum枚举类型代替:

Class GamePlayer{
private:
enum { NumTurns = 5 };
int scores[NumTurns];
……
}

事实上,enum成员不能被取到地址

另外,会有长得像函数的#define宏,它们甚至有参数:比如比较两个数哪个大。然而很多时候它们被展开后会带来很多料想不到的麻烦,这时最好采用template inline函数:

template <typename T>
inline void callWithMax(const T& a,const T& b)
{
f(a>b?a:b);
}

条款 3: 尽可能使用 const

const语法变化多端,但并不莫测高深。

char greeting[] = "hello";

char* p = greeting; //non-const pointer,non-const data

const char* p = greeting; //non-const pointer,const data

char* const p = greeting; //const pointer,non-const data

const char* const p = greeting; //const pointer,const data

如果const出现在星号左侧,表示被指物是常量,在右边表示指针自身是常量。若在左侧就不能改变被指物的值,在右侧就不能改变指针指向地址的值(比如将一个const数组指针指向的首地址自增1是不可能的)

函数声明式返回值为const的话,你可以很好应对一种情况:

if(返回值 = xxx) 在这里,你可能将==写成了=

由于你的失误将比较操作变成了赋值操作,这对于一个const返回值是会报错的!所以这很好地在编译期阻止了错误。

在class成员函数结尾加上const表明不允许此函数改动任何成员变量

如果某些成员函数即使在const成员函数内也可能会因为具体实现被修改,可以使用mutable关键字

public:

std::size_t length() const;
private:
char* pText;
mutable std::size_t textLength;
mutable bool lengthIsValid; std::size_t CTextBlock::length() const
{
if(!lengthIsValid){
textLength = std::strlen(pText); //现在你可以在const函数里修改成员值了
lengthIsValid = true; //现在你可以在const函数里修改成员值了
}
return textLength;
}

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

记住,在c++中,读取未初始化的值会导致不明确的行为,最佳操作是:在使用对象之前将它初始化。

对于内置类型,最好手工初始化:

例如: int x = 0;

const char* text = “A C-style string.”;

double d;

std::cin>>d; 以读取input stream的方式初始化

对于内置类型以外的东西,责任交给构造函数身上:将每个成员初始化。

注意,假设有一个构造函数是这样的:

XXX(string name, int age){

this->name = name;

this->age = age;

}

//这种叫做赋值,不叫初始化,不是最佳做法

初始化是指成员变量初始化动作发生在进入构造函数本体之前,时间更早(比进入默认构造函数时间还要早)

所以一种较佳写法是,使用成员初始化列表来初始化:

XXX(string name, int age):name(name),age(age){……} (这样似乎效率更高)

用成员初始化列表效率更高的原因是,「赋值」的写法会让构造函数先赋变量以默认值,然后再赋用户指定的值。而成员初始化列表是在进入构造函数之前就将你指定的值赋给了变量

我们可以规定成员初始化都用初始化列表

Important:

若有成员变量是const或引用(references)的话,它们就一定需要列表初始化,而不能被赋值

为了避免忘记这种特殊情况,最好的做法是都用成员初始化列表,它往往比赋值更高效

但是有时这种操作会使代码看起来不太美观,你就可以偷偷将一些“赋值表现得和初始化一样好”的变量改用赋值操作

Specially:

初始化次序取决于成员变量声明次序,也就是说,即使你在初始化列表里打乱了顺序,依旧按照声明顺序进行初始化

现在来关心一下static类型:

一般来说,在函数内部的static对象都叫做”local-static”,以外的叫做”non-local-static”

Local-static对象只会在函数调用之后才会被构造出来

而non…是在main后构造出来

现假设有两个cpp源文件,各自的类里有一个non-local-static对象,其中一个的初始化动作会使用到另一个static,但是被使用的对象可能还未初始化,此时会发生错误

此时可以用一个小设计:将两个类各自的non-local-static搬到属于自己的函数里,将它们变成local-static,函数会返回对象的引用。此操作保证了调用函数时,此函数包含的static对象一定会被初始化。很棒的是,只要你还未调用此函数,就不会有构造与析构成本

For example:

class FileSystem{
……
FileSystem& tfs(){
static FIleSystem fs;
return fs;
}
……
}; //这种函数很简单,通常会成为inlining候选人

OVER

EffictiveC++笔记 第1章的更多相关文章

  1. EffictiveC++笔记 第2章

    Chapter 2 构造 / 析构 / 赋值 条款 05:了解C++ 默默编写并调用哪些函数 如果你写下: class Empty{ }; 事实上编译器会帮你补全: class Empty{ publ ...

  2. EffictiveC++笔记 第3章

    Chapter 3 资源管理 条款13: 以对象管理资源 有时即使你顺利地写了对应对象的delete语句,但是前面的区域可能会有一个过早的return语句或者抛出了异常.它们一旦执行,控制流绝不会触及 ...

  3. Stealth视频教程学习笔记(第二章)

    Stealth视频教程学习笔记(第二章) 本文是对Unity官方视频教程Stealth的学习笔记.在此之前,本人整理了Stealth视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...

  4. Stealth视频教程学习笔记(第一章)

    Stealth视频教程学习笔记(第一章) 本文是对Unity官方视频教程Stealth的学习笔记.在此之前,本人整理了Stealth视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...

  5. 20145330《Java学习笔记》第一章课后练习8知识总结以及IDEA初次尝试

    20145330<Java学习笔记>第一章课后练习8知识总结以及IDEA初次尝试 题目: 如果C:\workspace\Hello\src中有Main.java如下: package cc ...

  6. java JDK8 学习笔记——第16章 整合数据库

    第十六章 整合数据库 16.1 JDBC入门 16.1.1 JDBC简介 1.JDBC是java联机数据库的标准规范.它定义了一组标准类与接口,标准API中的接口会有数据库厂商操作,称为JDBC驱动程 ...

  7. CSS3秘笈第三版涵盖HTML5学习笔记1~5章

    第一部分----CSS基础知识 第1章,CSS需要的HTML HTML越简单,对搜索引擎越友好 div是块级元素,span是行内元素 <section>标签包含一组相关的内容,就像一本书中 ...

  8. Android群英传笔记——第七章:Android动画机制和使用技巧

    Android群英传笔记--第七章:Android动画机制和使用技巧 想来,最 近忙的不可开交,都把看书给冷落了,还有好几本没有看完呢,速度得加快了 今天看了第七章,Android动画效果一直是人家中 ...

  9. Android群英传笔记——第六章:Android绘图机制与处理技巧

    Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...

随机推荐

  1. Nginx服务器导致CSS无法解析不起效果

    最近部署一个项目html,js正常加载,css也没有报404,css能够正常获取,只是浏览器无法解析,研究了一下发现,原来是配置Nginx的时候将/etc/nginx/nginx.conf的一行inc ...

  2. Mysql-自带的一些功能,基本用法(视图,触发器,事务,存储过程,函数,流程控制)

    一. 视图 二. 触发器 三. 事务 四. 存储过程 五. 函数 六. 流程控制 一 .视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用 ...

  3. Net Core动态加载webservice/WCF

    1.动态加载的目的 前端时间和顺丰对接了个项目(PS:顺丰的开发对外能力真的是掉粉),用的webservice 测试时用的无固定IP访问,正式版需要固定IP访问,我的理解是web服务都是全网络可以访问 ...

  4. 配置teredo,启用ipv6,xx-net

    最近使用XX-NET科学上网 ,提示要配置使用IPv6.根据github的上win10配置ipv6方式(https://github.com/XX-net/XX-Net/wiki/IPv6-Win10 ...

  5. 指针超强汇总(谨记优先级:() > [] > *)

    参考:http://blog.chinaunix.net/uid-20120277-id-5760985.html C语言所有复杂的指针声明,都是由各种声明嵌套构成的.如何解读复杂指针声明呢?右左法则 ...

  6. DCGAN 论文简单解读

    DCGAN的全称是Deep Convolution Generative Adversarial Networks(深度卷积生成对抗网络).是2014年Ian J.Goodfellow 的那篇开创性的 ...

  7. MySQL复制入门

    Ⅰ.复制类型 1.1 逻辑复制 记录每次逻辑操作 主从数据库可以不一致 1.2 物理逻辑复制 记录每次对于数据页的操作 主从数据物理严格一致 基于重做日志 说明: 如果一个块(页)修改了,就把这个修改 ...

  8. java.exe进程来源排查录

    解决后的一个小结:此处是一个tomcat端口,这种情况下,可以先在浏览器访问下看看效果,就可以快速定位 又发现一个简单的办法: 下面的定位过程,适用于各种场合 无意中发现有个进程开了好多端口,很奇怪 ...

  9. 你不知道的JavaScript--Item8 函数,方法,构造函数调用

    1.函数调用 Function绝对是JavaScript中的重中之重.在JavaScript中,Function承担了procedures, methods, constructors甚至是class ...

  10. websocket(一)--握手

    最近在琢磨怎么实现服务端的消息推送,因为以前都是通过客户端请求来获取信息的,如果需要实时信息就得轮询,比如通过ajax不停的请求. websocket相当于对HTTP协议进行了升级,客户端和服务端通过 ...