更高效的C++_More Effective CPP手记一之基础议题

来源:互联网 发布:北京精雕如何编程 编辑:程序博客网 时间:2024/06/14 23:56

基础议题


M1.指针与引用类型的选用

1.任何时候都不能使用只想控制的引用,引用一经定义,必须指向某个对象,之后不能改变。

2.如果设计中变量不能为空,应该使用引用,而且在使用时不需要对变量进行验证其合法性,效率要比指针要高。

3.指针与引用的一个重要区别是:指针可以指向NULL,而且可以重新指向另一个不同的对象,而引用初始化时被指定对象,之后不能改变。

4.当你重载某些操作符的时候,例如operator[],为防止不必要的误解时,应该选择引用。

5.总的来说,如果总是指向一个对象并且不改变指向,应该使用引用,否则在以下情况使用指针。

1)存在不指向对象的可能。

2)能够在不同时刻指向不同对象。


M2.使用C++风格的类型传唤

1.C风格转换缺点:

1)过于粗鲁,什么类型都能转换。

2)在程序语句中难以识别。

2.一般类似于C风格的转换,应用static_cast<type>(expression)替换。

(type) expression  ---->static_cast<type>(expression)

3.转换掉对象的const属性或volatileness属性,使用const_cast<type>(expression)

const Person p1;

Person& p2 = const_cast<Person>(p1);

4.dynamic_cast<type>(expression)可以将指向基类的指针或引用转换成派生类的指针或引用,前提是要有虚函数存在,此类只能用于继承关系的转换,转换失败将返回空指针或抛出异常。

5.函数指针转换,reinterpret_cast<type>(expression),其转换结果都是执行期定义,代码很难移植。

例:

typedef void (*FuncPtr)();

int doSomething();

FuncPtr func = &doSomething();//错误,类型不匹配!

FuncPtr func = reinterpret_cast<FuncPtr> &doSomething;//reinterpret转换可以迫使编译器以你的方法去看待他们

6.新的类型转换符不美观,但是这样程序更容易进行解析,他们云溪编译器检测出来原来不能发现的错误。


M3.不要对数组使用多态

1.例子:

class BST{};

class BalancedBST:public BST{};

有这样一个函数,打印出每一个BST对象的内容

void printBSTArray(ostream& s,const BST arrays[],int numElements)

{

for(int i = 0; i<numElements;++i)

s<<array[i];//假设BST类重载了操作符<<

}

当传入一个BST数组,可以正常运行,而传入一个BalancedBST类型,结果未定义,原理如下:

array[i]相当于*(array),而array十指相扣BST数组的首地址,数组中每个对象的大小是sizeof(BST),所以数组中个元素与array起始地址的间隔是i*sizeof(BST);

当你把BalancedBST对象数组传入到函数,编译器还是会认为数组中对象与起始地址的间隔是i*sizeof(BST),而此时每个对象的大小是sizeof(BalancedBST)。

2.自己理解:不要将参数设置为含有多态性的对象,改用指针或者引用。原因有二:

1)将多态性质的对象传入函数,会导致变量的拷贝,从而产生临时对象,降低性能。

2)将对象作为参数,会发生object slicing,并不会体现多态性质,只有引用和指针才会发生多态类型识别。


M4.避免无用的缺省构造函数

1.缺省的构造函数,可以在什么都不提供的情况下产生对象,有时候这种对象是无意义的。

2.提供无意义的缺省构造函数会影响类的工作效率,成员函数必须花费更多的时间,来进行测试对象的数据成员是否被正确初始化。

3.不使用缺省构造同样会带来不便

1)定义数组时,动态初始化问题。解决办法如下:

首先使用operator new[]为数组分配raw memory,避免浪费内存,

void* rawMemory = operator new[](10*sizeof(EquipmentPiece));

EquipmentPiece* bestPieces = static_cast<EquipmentPiece*>(rawMemory);

其次使用placement new进行函数构造

for(int i = 0;i<10;++i)

{

new (&bestPieces[i]) EquipmentPiece(ID)

}

注意:使用placement new构造的对象,需要使用opeator delete[](rawMemory);直接删除一个不使用new分配的内存指针,结果未定义。

2)无法再许多类模板中使用,此时对模板的定义也不能依赖于默认构造函数。

3)继承层次中,派生类很难与不提供默认构造函数的虚基类进行合作。

0 0
原创粉丝点击