- 1 让自己习惯C++
- 条款01:视C++为一个语言联邦
- 条款02:尽量以const,enum,inline替换#define
- 条款03:尽可能使用const
- 条款04:确定对象被使用前已先被初始化
Effictive C++ 学习记录 1 让自己习惯C++
Accustoming Yourself to C++
条款01:视C++为一个语言联邦View C++ as a federation of languages
C++ 可分为四个主要的次语言
- C 。 C++的区块、语句、预处理器、内置数据类型、数组、指针等来自于C。
- Object-Oriented C++。面向对象,类、封装、继承、多态、虚函数等。
- Template C++。泛型编程。
- STL。标准模板库,对容器、迭代器、算法以及函数对象进行配合和协调。
条款02:尽量以const,enum,inline替换#define
Perfer consts,enums,and inlines to #define
意为“宁愿使用编译器,替换使用预处理器”
当写下这样的语句:
#define PI 3.14
预处理器会将代码中的“PI”替换成“3.14”,“PI”不会进入记号表中,如果出现错误,追踪不知了来源的数字会浪费时间。
而且使用#define可能会造成语句混乱,当写下下面的语句时,由于define是整体替换,可能会改变原有的语句意思,例如,原本b的值为(3+13)×3=48,但是现在变成3+13×3=42。
#define a 3+13
int main(){
int b = a*3;
return 0;
}
为了解决#define带来的问题,可以使用常量const替换宏,这样就可以被编译器看到,从而进入记号表中。
const double PI = 3.14;
用常量const替换#define时,需要注意两种特殊情况:
- 定义常量指针
常量定义通常被放在头文件中,因此有必要将也指针声明为const,即,
const std::string stringname("BeiJing");
注:string对象会比char*更好点
- class 专属常量
为了使常量的作用域限制在类中,必须使其成为一个成员;同时保证此常量至多只有一份,必须使其成为一个static成员。
class GamePlayer{
private:
static const itn NumTurns = 5;// 常量声明式
int scores[NumTurns];// 使用该常量
};
注意,这里是声明并非定义!
如果不取NumTurns的地址,你可以不用提供定义式,但是如果取地址的话,就需要让编辑器看到一个定义式。
const int GamePlayer::NumTurns; // 定义式 无需设初值
注:一个对象可以声明多次,但只有一次定义!
初值可以放在定义式上,也可以放在声明式上(如果编辑器允许的话)。
当然,你也可以使用enum(枚举)。
class GamePlayer{
private:
enum {NumTurns = 5};
int scores[NumTurns];// 使用该常量
};
取enum的地址也不合法(有点像#define)
inline函数也可以用来解决#define带来的糟糕麻烦
例如,
template// 模板 inline void callWithMax(const T& a , const T& b){ f(a>b:a?b); }
小结:
- 对于单纯常量,最好以const或者enums替换#define
- 对于形似函数的宏,最好改用inline函数替换#define
条款03:尽可能使用const
Use const whenever possible
const奇妙之处在于,编辑器会强制实施它所允许的语义约束(指定一个不可被改动的对象)。
当修饰指针时,关键字const位于星号*的左边,表示被指物(所指对象)是常量(被指对象的值不能被改变);如果位于右边,则指针本身是常量(不能改变指针指向)。
关于迭代器
迭代器是根据指针塑膜出来的,就像一个T*指针,所以对迭代器进行约束就相当于对指针进行约束。
- 如果希望迭代器不能指向不同的东西,但是指向的值可以改动,即相当于声明一个 T* const 指针;
- 如果希望迭代器所指的东西不可改动,即相当于声明一个const T*指针,需要使用 const_iterator
std::vectorvec; const std::vector ::iterator iter = ver.begin(); // iter 相当于T* const *iter = 10; // 指向对象的值可以改变 iter++; // 错误 自身不能改变 std::vector ::const_iterator citer = ver.begin(); // citer 相当于const T* *citer = 10; // 错误 指向对象的值不可以改变 citer++; // 自身能改变
如果有需要改动参数或者local对象,否则请将它们设为const。
两个流行概念
- bitwise constness
const成员函数不能更改对象内任何non-static对象,但是可以用mutable关键字释放约束 - logical constness
const成员函数可以修改,但是要在客户端侦测不出的情况下?
小结:
- 将某些对象设为const
- 编辑器强制实施bitwise constness,但是你需要有自己的逻辑
令non-const版本调用const(实质等价实现)版本可避免代码重复
Make sure that objects are initialized before they’re used
最佳处理方法
永远在使用对象之前将它初始化
对于类对象,可以使用初始化列表对成员进行初始化
class People{
private:
int theAge;
string theName;
public:
People(int age,string name):theAge(age),theName(name){}
};
注意是设初值,而不是赋值,尤其是成员变量是const和引用,必须设初值。
两个成员变量的初始化带有次序性;
小结:
- 为内置型对象进行手工初始化
- 构建函数最好使用初始化列表
- 为免除“跨编译单元之初始化次序”的问题,请以local static 对象替换non-local static对象



