Item M1:指针和引用的区别
引用必须总是指向某个对象,任何情况下都不能使用指向空值的引用,不存在指向空值的引用意味着使用引用的代码效率比使用指针高,因为使用引用之前不需要测试引用的合法性。
指针可以被重新赋值指向另一个不同的对象,引用则一直指向初始化时指向的对象,以后都不能改变。
string s1("nancy");
string s2("clancy");
string &rs = s1;
string *ps = &s1;
rs = s2;//rs仍然引用s1,但是s1现在的值是clancy
ps = &s2;//ps指向s2,没有改变s1的值
Item M2:尽量使用C++风格的类型转换
double result = static_cast<double> (firstnum/secondnum);
class Widget { ... };
class SpecialWidget: public Widget { ... };
void update(SpecialWidget *psw);
SpecialWidget sw; // sw 是一个非 const 对象。
const SpecialWidget& csw = sw; // csw 是 sw 的一个引用,它是一个 const 对象
update(&csw); // 错误!不能传递一个 const SpecialWidget* 变量给一个处理 SpecialWidget*类型变量的函数
update(const_cast<SpecialWidget*>(&csw));// 正确,csw 的 const 被显示地转换掉,(csw 和 sw 两个变量值在 update函数中能被更新)
update((SpecialWidget*)&csw);//用了一个更难识别的C风格的类型转换
Widget *pw = new SpecialWidget;
update(pw);// 错误!pw 的类型是 Widget*,但是update 函数处理的是 SpecialWidget*类型
update(const_cast<SpecialWidget*>(pw));// 错误!const_cast 仅能被用在影响constness or volatileness 的地方上。不能用在向继承子类进行类型转换。
到目前为止,const_cast 最普通的用途就是转换掉对象的 const 属性。
dynamic_cast用于沿着类的继承关系向下进行类型转换,把指向基类的指针或引用转换成指向其派生类的指针或引用。
Widget *pw;
update(dynamic_cast<SpecialWidget*>(pw));// 正确,传递给 update 函数一个指针,是指向变量类型为 SpecialWidget 的 pw 的指针
void updateViaRef(SpecialWidget& rsw);
updateViaRef(dynamic_cast<SpecialWidget&>(*pw));//正确。 传递给 updateViaRef 函数SpecialWidget pw 指针
reinterpret_casts 的最普通的用途就是在函数指针类型之间进行转换
Item M3:不要对数组使用多态
类继承的最重要特性是可以通过指针和引用来操作派生类,具有行为的多态性。C++允许通过基类指针或引用来操作派生类数组。
class BST{ ...... };
class BalancedBST:public BST{.......};
void printBST(ostream& s,const BST array[ ],int num)
{
for(int i = 0;i<num;i++)
s<<array[i];
}
当你传入BST的数组是没有什么问题的。
现在传入BalanceBST呢?
BalanceBST bBST[10];
printBST(cout,bBST,10);
编译器会毫无怨言的接受,但是我们看看这个循环
for(int i = 0;i<num;++i)
s<<array[i];
我们知道array与array[i]之间的距离为i*sizeof(BST),所以编译器每次都是这样移动的。现在我们传入了派生类的对象,那么sizeof(BalanceBST)与sizeof(BST)不一定相等。所以array[i]移动的距离也不一定相等。
同样你用一个指向base的指针删除一个指向派生类的数组,也是有可能出现错误的。
Item M4:非必要不提供default constructor
必须有某些外来信息才能生成对象的class,不必拥有default constructor。
Item M5:对定制的“类型转换函数”保持警觉
class Rational {
public:
operator double() const; // 将Rational隐式转换为double
};
operator double函数可能导致非预期的函数被调用,解决方法是以一个功能对等的函数取代类型转换操作符,比如以asDouble替代operator double。
Item M6:区别increment操作符的前置和后置形式
int不允许连续两次使用后置式increment操作符,i++++不合法,但是++++i合法。
Item M7:千万不要重载&&,||和,操作符
Item M8:了解各种不同意义的new和delete
C++语言禁止为non-const reference参数产生临时对象,reference-to-const则没有这个问题。
Item 21:利用重载技术避免隐式类型转换
const UPInt operator+(const UPInt & l, const UPInt & r);
const UPInt operator+(const UPInt & l, int r);
const UPInt operator+(int l, const UPInt & r);
Item 22:考虑以操作符复合形式op=取代独身形式op
复合操作符比其对应的独身版本效率高,因为独身版本通常需要返回一个新对象,因此必须负担一个临时对象的构造和析构成本,而复合版本是直接将结果写入左端自变量,不需要产生一个临时对象来放置返回值。
Item 23:考虑使用其他程序库
Item 24:了解virtual functions、multiple inheritance、virtual base classes、runtime type identification的成本