条款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; }
函数指针的转型动作不具移植性,某些情况这样的转型可能导致不正确的结果,应尽量必变将函数指针转型。
版权声明:本文为博主原创文章,未经博主允许不得转载。