《Effectvie C++》读书笔记一
0.导读
1、 在真实项目的代码中,如果使用标准程序库元素,需要加上前缀std::。
2、 本书中,函数名和临时变量名都采用首个单词为小写,单词间大小写混合的方式。
3、 default构造函数包含二类:(1)不带实参;(2)每个参数都有缺省值。
4、 在构造函数前加上“explicit”的作用是:禁止编译器执行非预期的隐式类型转换。鼓励将构造函数声明为“explicit”类型。
5、 copy构造函数,如 Widget(const Widget& rhs);
copy assignment操作符,如 Widget&operator=(const Widget& rhs);
注意:如果出现 Widget w1= w0, 这个调用的是 copy构造函数,因为是在w1被定义时调用的,当然需要调用构造函数,但是如果Widget w1; w1=w0;这种情况下w1已经被定义好了,执行w1=w0时候只能调用copy assignment操作符了。
6、 函数形参出现类对象,一般要声明为const &类型比较好。
7、 声明一个指针变量,最好加上前缀p,声明一个引用,带上前缀r,成员函数加上前缀mf。
8、 TR1: Technical Report 1,描述加入C++标准库的诸多新机制;这些机能以class template和funciton template形式体现,针对的题目有hash table,reference-counting smart pointers,regular expression等,所有TR1组件被置于命名空间tr1内,后者嵌套与命名空间std内。
9、 Boost:是一个组织,也是一个网站,提供可移植性、同僚复审、源码开放的C++程序库,大多数TR1以boost的工作为基础,在编译器厂家于其C++程序库含入TR1之前,boost是开发人员首选的替代品。
1.让自己习惯C++
1、 C++: 多重泛型编程语言、一个同时支持过程形式、面向对象、函数形式、泛型形式、元编程形式的语言。相关语言组成的联邦而非单一语言。
2、 尽量以const, enum,inline替换#define,如
#define ASPECT_RATIO 1.653应该替换为: const double AspectRatio = 1.653;
字符串常量一般定义为: const std::string authorName(”aaa”);
如果要限制常量的作用域,将其放在类内部定义的话,需要声明为static类型,仅保留一个实体。
(1)新的编译器可以直接在类内部声明并赋值static常量。如
class Widget{
pubic:
static const double AspectRatio = 1.653;
…
};
但是还必须为AspectRatio在类外面定义一个空间
const double AspectRatio;//no initailization here
(2)对于有些旧的编译器而言,在头文件声明的static常量不能赋值,这种情况下需要在实现文件里定义该变量并且赋值。
class Widget{
pubic:
static const double AspectRatio;
…
};
const double Widget:AspectRatio = 1.653;
(3)如果编译器不允许“static 整数型 class 常量”完成“in class处置设定”,可以改用所谓的“the enum hack”补偿做法。
3、对于单纯常量,最好以const对象获enum替换#define,
对于形式函数的宏,最好改用inline函数替换#define。
3、 const std:vector<int>::iterator iter : iter不可以修改移动,所指的元素可以修改,类似 T* const p;
std::vector<int>::const_iterator iter2: iter2可以修改移动,但是所指的元素不可以修改,类似const T* P。
4、 类的operator操作符函数返回的类型最好定义为const类型,防止返回值再次被赋值。
5、 对于一般守则而言,转型是一个糟糕的想法。
6、 类中的函数推荐非const类型函数调用const类型函数,避免代码重复。Const成员函数调用none-const成员函数是一种错误的行为。
7、 对于内置类型变量,需要手工赋值初始化;对于类对象,也需要将其初始化。
8、 C++规定:对象的成员变量的初始化动作发生在进入构造函数本体之前。推荐采用成员初始化列表代替构造函数中的赋值动作,这样做的效率更高,而不要在构造函数本体中使用赋值操作,初始化列表列出的成员变量,其排列次序应该和它们在class中的声明次序相同
(1) 对于const和reference类型的成员变量,必须使用初始化列表。
(2) 如果构造函数中需要读写文件或数据库,则将这些动作写成单独的函数放在private区域供构造函数调用即可。
(3) Base classed先于derivedclass构造,class的成员变量以其声明的次序被初始化,即使它们在初始化列表中次序被打乱。
9、 C++对“定义于不同的编译单元的none-local static对象”的初始化相对次序并无明确定义,因此需要采用将non-local static对象替换为local static对象的方式,即单例模式。为了免除“跨编译单元初始化次序”的问题,请以local static对象替换non-local static 对象,这样就能保证对象的构造函数一定会被调用,而不是想在non-loca static情况下可能仅仅是调用了声明的对象,不是具体定义构造好的对象。
(1) non-local static
//widget.hpp
class Widget{
public:
int getSize() {return10;}
};
extern Widget w;
// Demo.hpp
Class Demo{
public:
Demo (param)
{
int size =w.getSize()//WARNNIG: Widget w可能还尚未初始化,程序崩溃
}
}
(2) local static 形式
//widget.hpp
class Widget{
public:
int getSize() {return10;}
};
//单例模式,reference-returning函数,
Widget& get Widget()
{
static Widget w;
return w;
}
// Demo.hpp
Class Demo{
public:
Demo (param)
{
int size = get Widget.getSize()//Widget w 已经被初始化
}
}
备注:从另一角度,这些函数“内含static对象”在多线程系统中具有不确定性, 任何一种non-const static对象,不论是local还是non-local,在多线程环境下“等待某事情发生”都会有麻烦,解决办法是:在程序的单线程启动阶段手工调用所有reference-returning函数,可以消除与初始化有关的“竞速形势力”(race conditions)。