条款1:仔细区别pointers和references
1、pointers和references之间的区别是:
a、没有所谓的null reference,一个reference必须总代表某个对象。pointer可以不指向任何对象。
b、pointer可以被重新赋值,指向另一个对象,reference却总是指向它最初获得的那个对象。
例子:
#include<string>
#include<iostream>
using namespace std;
int main(){
string s1("Nancy");
string s2("Jack");
string& rs = s1;//rs代表s1
string* ps = &s1;//ps指向s1
rs = s2; //rs仍代表s1,但s1的值变成了"Jack"
cout << s1 << endl;
ps = &s2; //ps指向s2
cout << s1 << endl;//s1的值没有变化
system("pause");
return 0;
}
2、一个reference必须总代表某个对象,因此reference必须有初值,但pointer没有这样的限制。
例子:
string& rs;//错误,reference必须初始化
string s("xy");
string& rs = s;//没问题,rs指向s
string* ps;//有效,但风险高
3、“没有所谓的null reference”这个事实意味着使用references可能会比使用pointers更富效率。因为使用reference之前不用测试其有效性。
例子:
void printDouble(const double& rd){
cout << rd; //不需要测试rd,它一定代表某个double
}
void printDouble(const double* pd){
if (pd) //检查是否为null pointer
cout << *pd;
}
4、考虑意向情况:
char* pc = 0;//将pointer设定为null
char& rc = *pc;//让reference代表null pointer的解引值
上述结果不可预料,C++对此没有定义,不应该写出这样的代码。
5、一般而言,当需要考虑“不指向任何对象”的可能性时,或是考虑“在不同时间指向不同对象”的能力时,应该使用pointer。当确定“总是会代表某个对象”,而且“一旦代表了该对象就不能够再改变”,或者重载某个操作符时,应该使用reference。
6、本条款结论:当你知道你需要指向某个东西,而且绝不会改变指向其他东西,或是当你实现一个操作符而其语法需求无法由pointers达成,你就应该选择references。任何其他时候,请采用pointers。
条款2:最好使用C++转型操作符
1、旧式转型存在以下问题:
a、它几乎允许你将任何类型转换为任何其他类型,这十分拙劣,如果每次转型都能够精确地指明意图则更好。
b、它们难以辨识,因为旧式转型的语法结构由一对小括号加上一个对象名称组成,而小括号和对象名称在C++的任何地方都有可能被使用。、
2、C++提供四种新式转型,见我另一篇博客http://blog.csdn.net/ruan875417/article/details/47281885条款27。3、static_cast 基本上拥有与C旧式转型相同的威力与意义,以及相同的限制。static_cast 不能移除表达式的常量性(constness)。
4、const_cast 用来改变表达式的常量性(constness)或变易性(volatileness)。
5、dynamic_cast要用来执行继承体系中“安全向下转型或跨系转型动作”,也就是说可以利用dynamic_cast将“指向base class objects的pointers或references”转型为“指向derived class objects的pointers或references,并且得知转型是否成功。如果失败,将返回空指针(当转型对象是指针)或抛出异常(当转型对象是引用)。dynamic_cast只能用来协助你巡航继承层体系之中,它无法应用在缺乏虚函数的类型上,也不能改变类型的常量性(constness)。
const_cast和dynamic_cast例子:
#include<iostream>
using namespace std;
class Base{
public:
virtual void print(){
cout << "Base" << endl;
}
};
class Derived :public Base{
public:
void print(){
cout << "Derived" << endl;
}
};
void doSomething(Derived* pd){
pd->print();
}
int main(){
Derived d;
const Derived& crd = d;
//doSomething(&crd);//错误,不能将const Derived*传给一个需要Derived*的函数
doSomething(const_cast<Derived*>(&crd));//正确,&csw的常量性去除了,csw在此函数中可被更改
doSomething((Derived*)(&crd));//正确,用了较难辨识的C旧式转型
Base* pb = new Derived;
//doSomething(pb);//错误,pb的静态类型是Base*,doSomething需要的是Derived*
//doSomething(const_cast<Derived*>(pb));//错误,const只能影响常量性和变易性
doSomething(dynamic_cast<Derived*>(pb));//正确
//doSomething(dynamic_cast<Derived*>(&crd));//错误,不能改变常量性
system("pause");
return 0;
}
6、reinterpret_cast的转换结果几乎总是与编译器相关,所以它不具移植性。reinterpret_cast的最常用用途是转换“函数指针”类型。
例子:
#include<iostream>
using namespace std;
int doSomething(){
cout << "doSomething" << endl;
}
int main(){
typedef void(*FuncPtr)();
FuncPtr funcPtrArray[10];
//funcPtrArray[0] = &doSomething;//错误,类型不符
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);//正确
system("pause");
return 0;
}
函数指针的转型动作不具移植性,某些情况这样的转型可能导致不正确的结果,应尽量必变将函数指针转型。