一、条款03:尽可能使用const
1、
char test[] = "hello";
const char *p = test; //数据为const
char * const p = test; //指针为const
const char* const p = test; //两者均为const
const在星号左边表示被指的为常量,在星号右边表示指针本身为常量;左右均有const表示被指物和指针均为常量。
void f1(const Widget* pw);
void f2(Widget const *pw);
函数f1和f2的参数含义一样,都是接受一个指针,这个指针指向的是常量的Widget对象。两种写法相同。
2、const与重载
(1)基于成员函数是否为const可以实现重载。如下就是两个重载成员函数:
Screen& display(ostream &os) {
do_display(os); return *this;
}
const Screen& display(ostream &os) const {
do_diaplay(); return *this;
}
(2)基于函数的引用形参是指向const对象还是非const对象,可以实现函数重载。如:
Record lookup(Account&);
Record lookup(const Account&);
如果传递的是const引用则只能调用有const引用形参的函数;如果传递的是非const引用则以上两者都可调用(非const对象即可初始化const引用也可初始化非const引用),但非const形参的初始化是精确匹配,将const引用初始化为非const对象需要通过转换实现。
(3)对指针形参的处理与(2)类似。
const对象的地址只能传递给带有指向const对象的指针形参的函数。可以将非const对象的指针传递给函数的const或非const类型的指针形参,同样,带有非const类型的指针形参函数是更好的匹配。
注意:不能基于指针本身是否为const来实现函数重载:
f(int *);
f(int *const);
此时,const用于修饰指针本身而不是修饰指针指向的类型。上述两种情况,都复制了指针,指针本身为const并没有关系。如下边第四点所讲所讲,当形参以副本传递时,不能基于形参是否为const实现重载。
正确的重载应该是:
f(int *);
f(const int *);
(4)当形参以副本传递时,不能基于形参是否为const实现重载。
Record lookup(Phone);
Record lookup(const Phone); //重复声明,不是重载
它们区别仅在于形参是否为const。不是重载原因在于实参传递方式。复制形参时并不考虑形参是否为const——函数操纵的只是副本。函数无法修改实参。结果,既将const对象传递给const形参也可传递给非const形参,这两种形参没区别(注意:这种const与非const的等价性仅适用于非引用形参)。
二、条款04 确定对象被使用前已先被初始化
1. 基类先于继承类初始化。
2. 类成员的初始化次序与成员声明次序一致,与成员初始化列表的顺序无关。
3. 为内置型对象进行手工初始化,因为C++不保证初始化他们。
4. 为避免“跨编译单元的初始化次序”问题,请用局部static对象替换非局部static对象。
编译单元是产生单一目标文件的那些源码,一般是单一源码加上其多保含的头文件。
C++对不同编译单元内的非局部static对象的初始化次序没有明确定义。
三、条款05 了解C++默默编写并调用哪些函数
四、条款06 若不想使用编译器自动生成的函数,就该明确拒绝
如果某个类完全禁止复制,如iostream类就不允许复制,那么似乎可以不定义复制构造函数;但是不定义的话,编译器会合成 一个。正确的做法是:将复制构造函数声明为private并不进行定义。”不定义“是防止类的友元或者类成员进行复制操作。
如类HomeForSale不能被复制,那么不是在该类中、而是专门为阻止拷贝动作而设计一个基类,在该基类中声明私有的复制构造函数:
class Uncopyable {
protected:
Uncopyable() {}
~Uncopyable() {}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
class HomeForSale: private Uncopyable{
//code
};
例如,上面专门用基类Uncopyale来防止拷贝动作。而为了防止HomeForSale对象被拷贝,所需要做的只是继承Uncopyale。