条款一:
把c++视为一个联邦式语言
条款二:
const,enum,inline替换#define
类里面的常量:两种方法:
第一种(对于某些旧式编译器不支持):在类里面声明:static const int NUM = 5;注意这是声明,如果需要取值还需在类外定义:const int 类::NUM;注意这里不需要在赋址。很奇怪!!
第二种:在类里面声明:static const int NUM ,在类外面定义:static const int NUM =1;
其次介绍了枚举的用法:在类里面 enum{NUM = 5};
条款三:
尽可能使用const
char greeting[] = "hello"
const char * p = greeting;//数组不能修改
char * const pp = greeting;//指针只能指向该数组
编译器强制实施bitwise constness,const 成员函数无法改变非const成员变量,除非成员变量被声明为mutable
const成员变量的初始化实在构造函数中!!
static成员变量初始化在类的外面:int const_test::tt = 0;变量在这里定义,不能放在初始化列表中
const int i=0:
int x =i;//ok
int & x=i;//error
const int & x = i;//ok
class Ration{。。。};
const Ration operator* (const Ration& lhs,const Ration& rhs);
Ration a,b,c;
(b*c)=a;//如果不是const,就会出现问题
条款四:
确定对象被使用前已被初始化
对象的成员变量初始化发生在进入构造函数本体之前,初始化列表。
自定义类型的成员变量自动调用default构造函数
初始化顺序与成员变量声明顺序一致
local static和non-local static:
不同编译单元的non_local static初始化顺序是不定的,因此不能在一个编译单元使用另一个编译单元的non_local static对象
class FileSystem{...};
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}
class Directory{...};
Directory::Directory()
{
tfs().成员函数()
}
Directory & tempDir()
{
static Directory td;
return td;
}
对于初始化问题:分为c形式和c++形式两个部分考虑,如int 型,如果没有给它初始化,那就没有初始值,如果是vector,会调用default构造。
静态全局变量有以下特点:
- 该变量在全局数据区分配内存;
- 未经初始化的静态全局变量会被程序自动初始化为0(自动变量的值是随机的,除非它被显式初始化);
- 静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的;
- 出现在类体外的函数定义不能指定关键字static;
- 静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
- 非静态成员函数可以任意地访问静态成员函数和静态数据成员;
- 静态成员函数不能访问非静态成员函数和非静态数据成员;
- 由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;
- 调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
<类名>::<静态成员函数名>(<参数表>)
调用类的静态成员函数。
条款五:
构造/析构/赋值运算
在一个内含“reference”成员或"const"成员的类,编译器不会为其生成copy assignment操作符
base classes将copy assignment声明为private,编译器不会为其生成copy assignment操作符
条款六
若不想使用编译器自动生成的函数,就该明确拒绝
将相应的成员函数声明为private并且不实现
使用uncopyable这样的base class
条款七
为多态基类声明virtual析构函数
如果虚构函数被声明为pure virtual,还需在类外面提供一份定义:类名::~类名(){}
最深层的class析构函数最先调用
条款八
别让异常逃离析构函数
两个异常同时存在,程序或结束执行或导致不明确行为
析构函数中:
try{db.close();}
catch{...}
{
记录
std::abort();
}
或
try{db.close();}
catch{...}
{
记录
}
条款九
绝对不在构造和析构过程中调用virtual函数
在base class构造期间,virtual函数不是virtual函数
通过一个static成员函数将derived class信息传递给base class。例子p51
explicit:关键字explicit可以禁止“单参数构造函数”被用于自动类型转换
条款10
在operator=返回reference to * this
条款11
在operator=中处理“自我赋值”
自我赋值安全性和异常安全性
Widget & Widget::operator=(const Widget& rhs)
{
Bitmap * porig = pb;
pb = new Bitmap(*rhs.pb);
delete porig;
return * this;
}
或
使用swap函数
条款12
复制对象时勿忘其每一个成分
当自己写copy函数时,derived class要在初始列表里面调用base class的copy构造函数,operator=()里面也要调用base class的operator=.eg:base_class::operator=()(rhs)