随笔-0  评论-0  文章-24  trackbacks-0
      条款1:仔细区别pointers和references
      首先你必须认知一点,没有所谓的null reference。一个reference必须总是代表某个对象。所以如果你有一个变量,其目的是用来指向(代表)另一个对象,但是也有可能它不指向(代表)任何对象,那么你应该使用pointer,因为你可以将pointer设为null。换个角度看,如果这个变量总是必须代表一个对象,也就是说如果你的设计并不允许这个变量为null,那么你应该使用reference。
      what about this?
      char *pc = 0;
      char &rc = *pc;
      这是有害的行为,其结果无可预期,编译器可以产生任何可能的输出。
      由于reference一定得代表某个对象,C++因此要求references必须有初值:
      string &rs;   //错误!references必须初始化
      string s("xyzzy");
      string &rs = s; //没问题,rs指向s
      但是pointers就没有这样的限制:
      string *ps; //未初始化的指针,有效,但风险高
      (没有所谓的null reference)这个事实意味使用references可能会比使用pointers更富效率。这是因为使用reference之前不需测试其有效性:
      void printDouble(const double &rd)
      {
               cout << rd; //不需测试rd; 它一定代表某个double
      } 
      如果使用pointers,通常就得测试它是否为null:
      void printDouble(const double *pd)
      {
               if (pd)   //检查是否为null pointer
               {
                        cout << *pd;
               }
      }
      pointers和references之间的另一个重要差异就是,pointers可以被重新赋值,指向另一个对象,reference却总是指向(代表)它最初获得的那个对象:
      string s1("Nancy");
      string s2("Clancy");
      
      string &rs = s1;   //rs代表s1
      string *ps = &s1;   //ps指向s1
      rs = s2;   //rs仍然代表s1,但是s1的值现在变成了"Clancy".
      
      ps = &s2;   //ps现在指向s2;s1没有变化
      还有其他情况也需要使用reference,例如当你实现某些操作符的时候。最常见的例子就是operator[]。这个操作符很特别地必须返回某种(能够被当做assignment赋值对象)的东西:
      vector<int> v(10);
      v[5] = 10;
      如果operator[]返回pointer,上述最后一个语句就必须写成这样子:
      *v[5] = 10;
      但这使v看起来好像是个以指针形成的vector,事实上它不是。为了这个因素,你应该总是令operator[]返回一个referenc。
      结论:当你知道你需要指向某个东西,而且绝不会改指向其他东西,或是当你实现一个操作符而其语法需求无法由pointers达成,你就应该选择references。任何其他时候,请采用pointers。
      条款2:最好使用C++转型操作符
      C++四个新的转型操作符:
      static_cast:转型操作。
      const_cast:移除某个对象的常量性。
      dynamic_cast:将指向base class objects之pointers或references转型为指向derived(或sibling base)class objects之pointers或references,并得知转型是否成功。如果转型失败,会以一个null指针(当转型对象是指针)或一个exception(当转型对象时reference)表现出来。第二个的用途是找出被某对象占用的内存的起始点。
      reinterpret_cast:最常用途是转换函数指针性别。
      typedef void (*FuncPtr)();
      FuncPtr funcPtrArray[10];
      假设由于某种原因,你希望将以下函数的一个指针放进funcPtrArray中:
      int doSomething();
      使用reinterpret_cast,可以强迫编译器了解你的意图:
      funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomethind);
 
      条款3:绝对不要以多态方式处理数组      
      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对象组成的数组传给此函数,没问题:
      BST BSTArray[10];
      printBSTArray(cout, BSTArray, 10);
      然而如果你将一个BalancedBST对象所组成的数组交给printBSTArray函数,会发生什么事:
      BalancedBST bBSTArray[10];
      printBSTArray(cout, bBSTArray, 10);
      你的编译器会被误导。这种情况下它仍假设数组中每一元素的大小是BST的大小,但其实每一元素的大小事BalanceBST的大小。由于derived classes通常比其base classes有更多的data members,所以derived class objects通常都比其base class objects来得大。这样的话,结果无可预期。
      如果你尝试通过一个base class指针,删除一个derived class objects组成的数组,那么上述问题还会以另一种不同面貌出现。下面是你可能做出的错误尝试:
      void deleteArray(ostream& logStream, BST array[])
      {
            logStream << "Deleting array at adress "
                           << static_cast<void*>(array) << '\n';
            delete [] array;
      }
      BalancedBST *balTreeArray = new BalancedBST[50];
      deleteArray(cout, balTreeArray);
      C++语言规格中说,通过base class指针删除一个由derived classes objects构成的数组,其结果未有定义。
      
            
posted on 2012-11-04 21:53 zhuxin 阅读(93) 评论(0)  编辑 收藏 引用 所属分类: More Effective C++

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理