zoukankan      html  css  js  c++  java
  • ###《More Effective C++》- 基础议题

    More Effective C++

    #@author:       gr
    #@date:         2015-05-11
    #@email:        forgerui@gmail.com
    

    一、仔细区别pointers和references

    1.1. 初始化

    指针可以不初始化,引用必须初始化为。

    引用没有null reference,指针可以设为NULL.

    //指针初始化为0,NULL,nullptr
    char *str = 0;
    int a = 1;
    //引用必须初始化,int &b;是错误的
    int &b = a;
    

    1.2. 效率

    因为不存在null reference,引用使用前不需要测试其有效性,效率比指针高一些。

    void print(const double& rd)
    {
    	cout << rd;		//不需要测试有效性
    }
    void print(const double* rd)
    {
    	if (*rd)
    		cout << rd;		//需要测试是否为空
    }
    

    1.3. 指向

    指针可以改变指向的对象,而reference始终指向最终指向的对象。

    string s1("aaa");
    string s2("bbb");
    string& rs = s1;
    string *ps = &s2;
    rs = s2;			//不变,仍指向s1,但s1值改变了
    ps = &s1;			//改变,改为指向s1
    

    在不同时间指向不同对象,使用指针;一旦代表了该对象就不能够改变,这时使用reference。比如operator[]操作符,应该使用引用;如果返回指针在赋值时需要写成下面的样子,很不直观,容易产生误解:

    vector<int> a(10);
    a[5] = 2;		//使用引用
    *a[5] = 2;		//使用指针
    

    二、最好使用C++转型操作符

    2.1. 新式转型

    static_cast<type>(expression)		//最常用的转型
    const_cast<type>(expression)		//将常量性去掉
    dynamic_cast<type>(expression)		//继承转换,将父类转为子类,无法转换,返回null或摄氏
    reinterpret_cast<type>(expression)	//与编译平台有关,不具移植性
    

    2.2. reinterpret_cast

    typedef void (*FuncPtr)();
    FuncPtr funcPtrArray[10];
    int doSomething();			//将doSomething放funcPtrArray中
    funcPtrArray[0] = &doSomething;		//错误,类型不符,无法存放
    funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);
    

    2.3. 先用旧式取代新式,方便升级

    #define static_cast(TYPE, EXPRESSION) ((TYPE) (EXPRESSION))
    #define const_cast(TYPE, EXPRESSION) ((TYPE) (EXPRESSION))
    

    虽然,新式转型又长又臭,但使用新式转型更加清晰,也会让你尽量减少转型的使用。

    三、绝对不要以多态(Polymorphism)方式处理数组

    3.1. 多态数组存在的问题

    class BST{...};
    class BalancedBST : public BST{...};
    
    void printBSTArray(ostream& s, const BST array[], int numElements)
    {
    	for (int i = 0; i < numElements; ++i)
    	{
    		s << array[i];
    	}
    }
    
    BST BSTArray[10];
    printBSTArray(cout, BSTArray, 10);		//表现良好
    
    BalancedBST bBSTArray[10];
    printBSTArray(cout, bBSTArray, 10);		//传入子类,存在问题
    

    如果想对子类的数组进行多态处理,往往因为子类的大小被解析成父类的大小,而无法达到想要的结果。这样会产生不可预测的结果。

    同样在进行数组删除时,同样也会遇到这样的问题,所以数组和多态不要一起使用

    牢记条款33所说“具体类不要继承自另一个具体类”可以避免这个错误。

    四、非必要不提供default constructors

    4.1. 无中生有

    有些类可以“无中生有”产生,然而有些类无法“无中生有”,因为这种产生的对象毫无意义。如:一个通信簿字段的class,如果没有获得外界指定的人名,产生出来的对象将毫无意义。这些对象不应该提供default constructor

    4.2. 缺乏default constructor带来的问题

    如下面的EquipmentPiece,它没有默认的构造函数,它将产生一些问题。

    class EquipmentPiece{
    public:
    	EquipmentPiece(int IDNumber);			//因为定义了其它ctors,所以编译器不会再生成defalut ctors
    };
    
    1. 在定义数组时,无法产生一个类型数组

       EquipmentPiece bestPiece[10];			//错误,无法调用EquipmentPiece ctors
       EquipmentPiece *bestPieces = new EquipmentPiece[10];		//错误
      

      解决这个问题方法是使用“指针数组”而非“对象数组”:

       typedef EquipmentPiece* PEP;
       PEP bestPiece[10];						//很好,定义10个元素的指针数组
       PEP *bestPieces = new PEP[10];		//也很好
       for (int i = 0; i < 10; ++i)
       	bestPieces[i] = new EquipmentPiece( ID Number );
      
    2. 它们不适用于许多template-based container classes,这些contrainer希望实例化的目标得有一个default constructors

       template <typename T>
       class Array{
       public:
       	Array (int size);
       private:
       	T *data;
       };
       template <typename T>
       Array<T>::Array(int size)
       {
       	data = new T[size];			//会报错,需要调用default ctors
       }
      

    解决方法是谨慎设计template,消除对default ctors的需求。比如vector就不要求默认构造函数。

    1. virtual base classes时存在问题

      可能要求所有派生类都要提供virtual base classconstructors自变量。

    4.3. 提供默认构造函数存在的问题

    1. 其它成员需要检查ID是否存在,使其它member function变得复杂。
    2. 影响class的效率。
  • 相关阅读:
    用户使用调查报告
    Beta总结
    Beta冲刺Day7
    Beta冲刺Day6
    Beta冲刺Day5
    Beta冲刺Day4
    Beta冲刺Day3
    Beta冲刺Day2
    Beta冲刺Day1
    Beta预备
  • 原文地址:https://www.cnblogs.com/gr-nick/p/4563658.html
Copyright © 2011-2022 走看看