有關引用和別名以及指針之間的關聯和區別

引用是別名而非指針 
      引用(reference)是一個現有對象的別名. 
      用對象來初始化引用之後,那麼對象的名字或引用的名字都可以用於指向(refer to)該對象:       int a = 12; 
      int &ra = a; // ra是a的別名       --ra;     // a == 11       a = 10; // ra == 10 
      int *ip = &ra // ip指向a 
      人們常常會將引用和指針混淆,原因大概在於C++編譯器通常採用指針的方式實現引用,但引用其實不是指針,其行爲和指針並不相同. 
      在引用和指針之間存在三大區別:其一,不存在空引用(null reference);其二,所有引用都要初始化;其三,一個引用永遠指向用來對它初始化的那個對象.例如,在先前的例子中,引用ra在整個生命期內都指 向a.絕大多數對引用的誤用都滋生於對這三大區別的誤解. 
      一些編譯器可以捕捉到那些明顯的創建空引用的嘗試: 
      Employee &anEmployee = *static_cast<Employee*>(0); // 錯誤!       然而,編譯器可能無法偵測到不那麼明顯的創建空引用的嘗試,從而導致在運行期發生未定義行爲: 
      Employee *getAnEmployee();       // ... 
      Employee &anEmployee = *getAnEmployee();       if( &anEmployee == 0 ) // 未定義的行爲 
      如果getAnEmployee返回的是一個空指針,那麼其後代碼的行爲就是未定義的.在這個例子中,最好使用一個指針來存放getAnEmployee返回的結果.       Employee *employee = getAnEmployee();       if( employee ) // ... 
      引用必須初始化的要求,意味着當一個引用初始化時,它所指向的那個對象必須存在.這一點很重要,因此請記住:一個引用就是在該引用被初始化之前已經存在的 一個對象的別名.一旦一個引用被初始化去指向一個特定的對象,那麼該引用以後就不可以再指向別的對象;在一個引用的整個生命期內,該引用被綁定到用於初始 化的那個對象上.實際上,一個引用完成其初始化後,就只是初始化它的那個對象的別名了.這個"別名"屬性似的引用常常成爲函數形參的優秀選擇.在以下 swap函數模板中,形參a和b乃是傳遞給調用的實參的別名:       template <typename T> 
 
 

      void swap( T &a, T &b ) {           T temp(a);           a = b;           b = temp;       } 
      // ... 
      int x = 1, y = 2; 
      swap( x, y ); // x == 2, y == 1 
      以上對swap的整個調用期間,a是x的別名,b是y的別名.提醒一下,引用所指向的對象可以沒有名字,因此引用可用於爲沒有名字的對象賦予一個方便的名字: 
      int grades[MAX];       // ... 
      swap( grades[i], grades[j] ); 
      當swap中的形參a和b分別被用實參grades[i]和grades[j]初始化以後,這兩個沒有名字的數組元素就可以通過別名a和b進行操縱了.爲 了簡化和優化,還可以採用更直接的方式來使用這個屬性.考慮如下函數,它用於設置二維數組中一個特定元素: 
      inline void set_2d( float *a, int m, int i, int j ) {           a[i*m+j] = a[i*m+j] * a[i*m+i] + a[i*m+j]; // 哎呀!       可以將註釋有"哎呀!"的那行代碼替代爲更簡單的版本,該版本利用了引用,而且還帶來額外的好處,那就是正確(看出錯在哪兒了嗎?反正我第一眼沒看出來.) 
      inline void set_2d( float *a, int m, int i, int j ) {           float &r = a[i*m+j];           r = r * r * r;       } 
      一個指向非常量的引用是不可以用字面值或臨時值進行初始化的:       doulbe &d = 12.3; // Error!!! 
      swap( std::string("Helo"), std::string(", World") ); // Error!!!       然而,一個指向常量的引用就可以:       const double &cd = 12.3;       template <typename T> 
      T add( const T &a, const T &b ) {           return a + b;       } 
      // ... 
      const std::string &greeting 
          = add(std::string("Hello"), std::string(", World")); // OK 
 
 

      當一個指向常量的引用採用一個字面值進行初始化時,該引用實際上被設置爲指向"採用該字面值初始化"的一個臨時位置.因此,cd並非真的指向字面值 12.3,而是指向一個採用12.3初始化的,類型爲double的臨時變量.greeting引用則指向對add的調用所返回的無名臨時string對 象.一般來說,這類臨時對象在創建他們的表達式的末尾被銷燬(確切的說,就是離開作用域並且析構函數被調用).然而,當這類臨時對象用於初始化一個指向常 量的引用時,在引用指向它們期間,這些臨時對象會一直存在.
發佈了27 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章