More Effective C++ 第一部分 基础议题

来源:互联网 发布:淘宝手表拍卖有猫腻 编辑:程序博客网 时间:2024/06/06 13:13

1.仔细区别pointers和references


当你知道你需要指向某个东西,而且绝不会改变其指向其他的东西,或当你实现一个操作符而语法需求无法由pointer达成,你就应该选用reference.任何其他时候,请使用pointers.

指向NULL

一个reference必须代表某个对象,即不可为NULL。而pointer 可以。若使用reference将意味着不再考虑reference成为NULL的可能性。也就意味着使用reference可能比pointer更有效率,因为不需要考虑NULL的问题。
由于该特性,C++要求reference必须有初值,而pointer并无此要求。

重新赋值

pointer可以重新赋值,而reference不可以,reference总是指向最初获得的那个对象。(类似const)
如果希望在不同时刻指向不同对象,那么只能使用pointer。若希望一旦代表了某个对象就不能再改变,就应当选用reference。

其他使用reference的情况

最常见的例子就是operator[],例如:

vector<int> v(10);v[5] = 10;//operator[]返回reference*v[5] = 10;//operator[]返回pointer

若使用pointer可能会误以为vector内存的是指针。


2.最好使用C++转型操作符

新式转型操作符用途更加专一,并且更能表明程序员的意图(例如使用const_cast),也更容易被机器和人类识别。并提供安全性(dynamic_cast)。还提供一些旧式转型无法提供的功能(reinterpret_cast)。

reinterpret_cast:用来转换函数类型指针,不具可移植性,非十分迫不得已,不应使用。

typedef void (*FuncPtr)();FuncPtr funcPtrArray[10];//返回类型为void的函数指针数组int doSomething();//返回类型为intfuncPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);

3.绝不要以多态方式处理数组

Base类型数组 array[i] 代表的是 *( array + i * sizeof(Base) ),若将Base类型的数组以多态的形式指向Derived类型的对象数组,那么编译器的寻址方式依然是使用sizeof(Base),将导致未定义的结果。例如:

#include <iostream>class Base{public:    int a = 1;};class Derived: public Base{public:    int b = 2;};//该函数接受Base类型的指针,并输出其内容。void func(const Base array[],int num){    for (int i = 0; i < num; i++) {        std::cout<<array[i].a<<"  ";    }    std::cout<<std::endl;}int main(int argc, const char * argv[]) {    Base baseArray[10];    Derived derivedArray[10];    func(baseArray,10);//传入Base类型数组,没问题    func(derivedArray, 10);//传入Derived类型数组,并未报错,但结果与期望的不一致。    return 0;}该程序输出1  1  1  1  1  1  1  1  1  1  1  2  1  2  1  2  1  2  1  2  Program ended with exit code: 0

我们可以看到使用多态的方式处理数组带来的错误,我们也可以根据输出结果来推断编译器解释array[i]时使用的是 *( array + i * sizeof(Base) ),而不因为array是其派生类类型而做出改变。


4.非必要不提供default constructor

default constructor为参数为空的构造函数。缺乏default constructor将会带来2个缺点:
1.无法产生数组。因为没有方法可以为数组中的对象知道constructor变量。
2.不适用于许多template-base container classes。

但是强行提供default constructor将会带来程序质量的下降,比如一个需要ID初始化的类,若提供default constructor便要在程序中检查其ID有无被正确初始化,使得效率降低,代码量增加。

0 0