先看**:
1 #include 2上面的**可以編譯通過(gcc和vs2005下均測試通過),但是如果將第16行的const修飾符去掉,編譯就不能通過,報錯說沒有匹配的函式,這是為什麼?using
namespace
std;34
class
a {};56
classb7
10 b(a&a){}
11};
1213
class b1: publicb14
18};
1920
intmain()
21
分析:非const的引用引數只能是相同型別,const的引用引數可以傳相關型別的引數進來,加上const才能接受"右值(right value)"引用。b(a& a){} 不但是乙個建構函式,而且是乙個自定義的型別轉換操作(a->b),如果要去掉這種非有意的自定義型別轉換,使用 explicit b(a& a){}。
b(a& a){}是乙個隱式的型別轉換函式,當執行b1 b1(a)時會自動呼叫這個函式將a轉換成b型別的臨時物件b。這種系統自動生成的臨時物件都是const的,而const物件是無法轉換成非const物件的,所以b1(const b& b):b(b)這裡一定要加const.
乙個非const引用,只能引用與其型別完全相同的物件,或者是其派生類的物件,如:
b & refb = objectb ; b & refb = objectb1 都是合法的,但是 b & refb = objecta 就不是合法的
因為 a 與 b的型別不相同,且不是b的派生類,所以編譯時會報錯,於是 "a a; b1 b1(a)" 就不能通過,簡化一下就相當於" b & b = a".
乙個const引用滿足非const引用的特性的同時,還有很重要的一點,const引用可以引用乙個與其型別完全不相同的型別(因為編譯器會生成乙個轉換後可引用的臨時物件),前提是被引用的型別可以轉換為引用的型別(編譯器自定義的型別提公升,或者是使用者自定義的型別轉換,如上面的 b(a& a) )
舉個例子:
const int & ivalue = 3.14; 就是ok的,這裡使用編譯器內部的型別轉換 double -> int.
const b & b = a; 也是ok的,因為使用 b( a &a) 可以將 a->b ,於是 const b &b = a; 的背後,編譯器所做的就是:
const b tempb( a ); //呼叫 b( a &a)
const b &b = tempb;
ps: 為什麼在const引用情況下,編譯器會生成乙個可被引用的臨時物件,原因很簡單,你是用乙個const引用來操作這個臨時物件,所以,這個臨時物件的狀態是不會變的,也就是安全的(當然,如果你把const引用const_cast成乙個非const引用來操作這個編譯器生成的臨時物件,那麼結果是未定義的).
const &是可以重新構造臨時物件,非const &不可以,如果編譯器不設這個限制,那麼將有十分古怪的結果發生,會發生編譯器自己構造乙個物件,對它進生一系列複雜的操作之後扔掉,這一般不是程式設計師要做的事。因此,c++一般規定,編譯器自行構造的臨時物件一定是const的。
more effective c++裡面對這個問題講得很清楚(m19:理解臨時物件的**)
下面還有乙個小例子:
string foo( );
void bar(string & s);
那麼下面的表示式將是非法的:
bar(foo( ));
bar("hello world");
原因在於 foo( ) 和 "hello world" 串都會產生乙個臨時物件,而在 c++ 中,這些臨時物件都是const 型別的。因此上面的表示式就是試圖將乙個 const 型別的物件轉換為非 const 型別,這是非法的。引用型引數應該在能被定義為 const 的情況下,盡量定義為const的。
C 中的一類臨時物件
類名 引數名 這樣的物件是臨時物件,不能取位址,不能被引用,不過可以給同型別的其他物件賦值,該臨時物件定以後可以進行一次操作,然後立即銷毀。當我們定義乙個物件以後並不想立即給它賦初值,而是以後給它賦初值,在稍後賦初值的時候,該類臨時物件就可以發揮作用了。下面給出乙個例子 include includ...
C 中的臨時物件
我們知道在c 的建立物件是乙個費時,費空間的乙個操作。有些固然是必不可少,但還有一些物件卻在我們不知道的情況下被建立了。通常以下三種情況會產生臨時物件 1,以值的方式給函式傳參 2,型別轉換 3,函式需要返回乙個物件時 現在我們依次看這三種情況 一,以值的方式給函式傳參。我們知道給函式傳參有兩種方式...
C 中的臨時物件
1,臨時物件神秘在於不知不覺就請入程式當中,並且給程式帶來了一定的問題 2,下面的程式輸出什麼?為什麼?1 include 2 3class test411 12 test 這裡程式作者想要 復用,直接呼叫已經構造好的函式來完成沒有引數的建構函式的函式體 1316 17void print 1821...