1. 当你看到赋值符号“=”时,一定要小心, 因为赋值操作也可以调用copy构造函数:
Widget w1;
Widget w2 = w1; //调用copy构造函数。
Widget w3, w4;
w3 = w4 //调用赋值操作符。
copy 构造函数和copy赋值函数的区别是, 如果一个新对象被定义, 一定有个构造函数被调用,如果没有新对象被定义, 就不会有构造函数调用。
2. In-class 初值设定只允许对整数常量进行, 如果你的编译器不支持上述语法, 你可以将初值放在定义式:
class CostE
{
private:
static const double dFactor; //static class 常量声明位于头文件内
};
const double CostE::dFactor = 1.11; // 位于实现文件内
万一编译器不允许“static 整型class常量”进行 “in-class”初值设定, 可改用所谓的“the enum hack”补偿方法。
class GamePalyer
{
private:
enum {NumTurns = 5};
int scores[NumTurns];
};
3. 宏定义的错误
#define MAX(a, b) f((a) > (b)? (a) : (b))
int a = 5, b = 0;
MAX(++a, b); //a被累加两次
MAx(++a, b+10); //a被累加一次
4. const ×
const char* p = strA; //non-const pointer, const data
char* const p = strA; //const pointer, non-const data
const char* cosnt p = strA;//cosnt pointer, const data
const 出现在星号左侧, 表示被指物是常量; 如果出现在星号右侧, 表示指针是常量; 如果出现在星号两侧, 表示被指物和指针两边都是常量。
const char* p 和 char const * p 是等价的。
5. const_iterator 就像 const T*, 迭代器所指的东西不可被改动。
6. 令函数返回一个常量值, 可以降低因客户错误而造成的意外, 而又不放弃安全性和高效性。
const Rational operator* (const Rational& lhs, const Rational& rhs);
返回一个const对象的好处时, 如果客户把== 误写成=,那么编译错误。
Rational a, b, c;
...
if (a*b = c)
7. const 成员函数, 形式为 void func1()const, 其作用是确认该成员函数可用于const对象身上。
class A
{
...
void func1();
void func2() const;
...
}
const A objA;
A objB;
objA.func1(); //非法, 因为func1是非const成员函数, 不能用于const对象。
objA.func2(); //合法, 只有const对象可以用于const函数。
objB.func2(); //合法, 非const对象也可以调用const函数
8. const成员函数中如果确实要修改成员变量, 则定义成员变量为mutable。
9. override operator [] 下标重载
1) [] 只能通过成员函数重载.
2) [] 返回类型为reference, 如果是值, 不能修改元素。
3) [] 应该重载const成员函数版本和non-const成员函数版本, 以支持const对象的读值操作。
10. 初始化列表
1)C++规定, 对象的成员变量初始化发生在进去构造函数本体之前, 因此,构造函数中的成员变量赋值都是赋值操作,而非初始化。
2)构造函数的最佳写法是使用所谓的 member intialization list(成员初始化列)替换赋值操作。 成员初始化列效率更高。 因为通过赋值构造, 首先使用default构造函数为成员变量设初值, 然后再对它赋予新值。成员初始化列的做法避免了这一问题。
3)const 成员变量或reference,他们一定需要初值, 不能被赋值,。 必须使用初始化列。
11. 成员初始化次序: base 早于 derived, 成员变量总是以器声明次序被初始化。为避免阅读时迷惑, 在成员初始列中列各个成员时, 最好总是以声明次序为次序。