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

Posted zhangqixiang5449

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了More Effective C++ 第一部分 基础议题相关的知识,希望对你有一定的参考价值。

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();//返回类型为int
funcPtrArray[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有无被正确初始化,使得效率降低,代码量增加。

以上是关于More Effective C++ 第一部分 基础议题的主要内容,如果未能解决你的问题,请参考以下文章

More Effective C++ 第五部分 技术

《More Effective C++》总结笔记——异常

《More Effective C++》总结笔记

Effective C++(第三版)笔记 ---- 第一部分让自己习惯C++

More Effective C++ 第三部分 异常

《More Effective C++》阅读笔记