Effective C++ 笔记一 让自己习惯C++

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

C++是个多重范型编程语言,一个同时支持面向过程形式、面向对象形式、函数形式、泛型形式、元编程形式的寓言。

将C++视为几个子语言:

传统C:区块、语句、预处理器、内置数据类型、数组、指针。没有模板、没有异常、没有重载。

面向对象C++:类(包括构造函数析构函数)、封装、继承、多态、虚函数。

Template C++:泛型编程、模板元编程。

STL:容器、迭代器、算法、函数对象(仿函数)。

记住:

C++高效编程守则视状况而变化,取决于你使用C++的哪一部分。

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

用编译器代替预处理器。#define不被视为语言的一部分,所使用的名称不进入记号表。

 1 #define ASPECT_RATIO 1.653
 2 const double AspectRatio = 1.653;
 3 const char* const authorName = "Scott Meyers";
 4 const std::string authorName2("Scott Meyers");
 5 class GamePlayer {
 6     static const int NumTurns = 5;
 7     enum { NumTurns2 = 5 };// 一个属于枚举类型的数值可以当做int使用
 8     int scores[NumTurns];
 9 };
10 const int GamePlayer::NumTurns;// 需要取地址时不能省略
11 #define CALL_WITH_MAX(a, b) f((a)>(b)?(a):(b))
12 template<typename T>
13 inline void callWithMax(const T& a, const T& b) {
14     f(a>b?a:b);
15 }

记住:

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

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

条款03:尽可能使用const

const 允许指定一个不能被改动的约束,而编译器会强制实施这项约束。

const 可以在 classes 外部修饰 global 或 namespace 作用域中的常量,或修饰文件、函数或区块作用于中被声明为 static 的对象。也可以修饰 classes 内部的 static 和 non-static 成员变量。面对指针,也可以指出指针自身、指针所指物或两者都是 const:如果关键字 const 出现在星号左边,表示被指物是常量;出现在星号右边,表示指针自身是常量;出现在星号两边,表示被指物和指针两者都是常量。

STL迭代器声明为 const 相当声明指针为 const,迭代器不得指向不同的东西,但它所指的值是可以改动的。const_iterator 所指的东西不可改动。

在函数声明式内,const 可以和函数返回值、各参数、函数自身(成员函数)产生关联。令函数返回一个常量值,可以避免客户错误造成的意外。将 const 实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上:第一,它使 class 接口比较容易理解;第二,它使操作 const 对象成为可能,以 pass by reference-to-const 方式传递对象。两个成员函数如果只是常量性不同可以被重载。

一个const成员函数可以修改它处理的对象内的某些数据,但只有在客户端侦测不出的情况下才可以,例如高速缓存的文本区块的长度等。mutable 关键字修饰的成员可以被更改。

运用 const 成员函数实现出其 non-const 孪生兄弟来避免代码重复。

记住:

将某些东西声明为 const 可帮助编译器侦测出错误用法。const 可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。

编译器强制实施 bitwise constness,但你编写程序时应该使用 conceptual constness(概念上的常量性)。

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

static 对象,其寿命从被构造出来直到程序结束为止,因此 stack 和 heap-based 对象都被排除。这种对象包括 global 对象、定义于 namespace 作用域内的对象、在 classes 内、在函数内、以及在 file 作用域内被声明为 static 的对象。函数内的 static 对象称为 local static 对象,其他 static 对象称为 non-local static 对象。程序结束时 static 对象会被自动销毁,它们的析构函数会在 main() 结束时被自动调用。

编译单元是指产出单一目标文件的那些源码。基本上是单一源码文件加上其所含入的头文件。

多个编译单元内的 non-local static 对象经由模板隐式具现化形成,不能决定正确的初始化次序。

将每个 non-local static 对象搬到自己的专属函数内,该对象在此函数内被声明为 static。这些函数返回一个指向他所含对象的引用,non-local static 对象呗 local static 对象替换了。这是单例模式的一个常见实现手法。

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

记住:

为内置型对象进行手工初始化,因为C++不保证初始化它们。

构造函数最好使用成员初值列,而不要在构造函数本体内使用赋值操作。初值列列出的成员,其排列次序应该和它们在class中的声明次序相同。

为避免跨编译单元的初始化次序问题,以 local static 对象替换 non-local static 对象。

时间: 2024-10-02 10:15:55

Effective C++ 笔记一 让自己习惯C++的相关文章

【Effective C++ 笔记】让自己习惯C++

最近在读 Effective C++,想要做点笔记,归类和书中的每个模块一样,但跟模块里的具体顺序可能不太一致.不会对书中每个细节都涉及,主要记下自己觉得重要的内容. What is C++? C++ 是一个多重范型编程语言( multiparadigm programming language),一个同时支持过程形式(procedural).面向对象形式(object-oriented).函数形式(functional).泛型形式(genetic).元编程形式(metaprogramming)

Effective c++(笔记) 之 类与函数的设计声明中常遇到的问题

1.当我们开始去敲代码的时候,想过这个问题么?怎么去设计一个类? 或者对于程序员来说,写代码真的就如同搬砖一样,每天都干的事情,但是我们是否曾想过,在c++的代码中怎么样去设计一个类?我觉得这个问题可比我们"搬砖"重要的多,大家说不是么? 这个答案在本博客中会细细道来,当我们设计一个类时,其实会出现很多问题,例如:我们是否应该在类中编写copy constructor 和assignment运算符(这个上篇博客中已说明),另外,我们是让编写的函数成为类的成员函数还是友元还是非成员函数,

Effective c++(笔记)----类与函数之实现

上篇博客中集中说明了在设计一个类的时候常遇到的问题,当然博客中还夹杂着我随时想到的一些知识,发现自己写博客没很多人写的好,可能是自己语言不会组织,要么就是写的东西大家不愿意看,反正是有这方面的专业问题或者博客中有什么明显的错误和问题,大家提出来,我也好改进哈! 回归正题,这篇博客就大概的把Effective c++中类与函数这节看到的知识点做个笔记. 设计好一个类后,自己就要去实现这个类(实现类中的成员函数.友元.非成员函数等) 可能大家会遇到以下问题 1.在类的成员函数中,尽量避免返回内部数据

Effective C++笔记:构造/析构/赋值运算

条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函数时,编译器会给我们构造默认的. 当成员变量里有const对象或引用类型时,编译器会不能合成默认的拷贝赋值函数:当一个基类把它的拷贝赋值函数定义为private时,它的派生类也不无生成默认的拷贝赋值函数,因为它无法完成基类成份的赋值. 条款06:若不想使用编译器自动生成的函数,就该明确拒绝 将拷贝构

Effective C++笔记06:继承与面向对象设计

关于OOP 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private,也可以是virtual或non-virtual. 2,成员函数的各个选项:virtual或non-virtual或pure-virtual. 3,成员函数和其他语言特性的交互影响:缺省参数值与virtual函数有什么交互影响?继承如何影响C++的名称查找规则?设计选项有如些?如果class的行为

Effective c++(笔记)之继承关系与面向对象设计

1.公有继承(public inheritance) 意味着"是一种"(isa)的关系 解析:一定要深刻理解这句话的含义,不要认为这大家都知道,本来我也这样认为,当我看完这章后,就不这样认为了. 公有继承可以这样理解,如果令class D以public 的形式继承了class B ,那么可以这样认为,每一个类型为D的对象同时也可以认为是类型为B的对象,但反过来是不成立的,对象D是更特殊化更具体的的概念,而B是更一般化的概念,每一件事情只要能够施行于基类对象身上,就一定可以应用于派生类对

Effective C++笔记05:实现

条款26:尽可能延后变量定义式的出现时间 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开始定义的对象并没有被使用,而付出了构造成本来析构成本. 所以我们应该在定义对象时,尽可能的延后,甚至直到非得使用该变量前一刻为止,应该尝试延后这份定义直到能够给它初值实参为止. 这样做的好处是:不仅可以避免构造(析构)非必要对象,还可以避免无意义的default构造行为. 遇到循环怎么办?此时往往我

[Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+1}" 反射获取函数源代码的功能很强大,使用函数对象的toString方法有严重的局限性.toString方法的局限性ECMAScript标准对函数对象的toString方法的返回结果(即该字符串)并没有任何要求.这意味着不同的js引擎将产生不同的字符串,甚至产生的字符串与该函数并不相关. 如果函数

[Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式传递给eval函数以达到同样的功能.程序员面临一个选择:应该将代码表示为函数还是字符串?毫无疑问,应该将代码表示为函数.字符串表示代码不够灵活的一个重要原因是:它们不是闭包. 闭包回顾 看下面这个图 js的函数值包含了比调用它们时执行所需要的代码还要多的信息.而且js函数值还在内部存储它们可能会引用