C/C++左值性精髓
(二)哪些運算式是左值,哪些是右值?
3. 函數調用運算式和強制轉換
對於函數調用運算式和強制轉換運算式的結果,在C中都屬於右值;C++由於增加了參考型別,結果為引用的函數調用運算式和強制轉換運算式都屬於左值,樣本如下:
int& fun1( int & r ){ return r; }
int fun2( void ){ return 10; }
int i = 20;
fun2( ) = 30; //A
cout << ( fun1( i ) = 30 ); //B
( int & )10 = 20; //C
( const int & )10 = 20; //D
( int & )i = 40; //E
( double & )i = 50; //F
cout << ( double & )i; //G
A: fun2的傳回值是一個右值,不能作為內建賦值運算式的左運算元,因此A是錯誤的;
B: fun1返回一個引用,屬於左值,因此可以作為內建賦值運算子的左運算元;
C: C試圖將一個右值強制轉換為引用,但是,只有const引用才能引用一個右值,因此錯 誤;
D: D比C進步了一點,強制轉換為const引用,但仍然是錯誤的,因為const引用屬於不可修改的左值,不能通過const引用修改其引用的對象;
E: E將一個int變數強制轉換為int引用並被修改。這個運算式容易出現誤解,以為i被臨時轉換為一個引用,其實不然,( int& )i只是產生一個引用到i的臨時引用,i是被引用的對象而非引用本身,被修改的是i的值;
F、G:F和G與E一樣,都產生一個引用到i的臨時引用,但存在兩個問題,一是由於i的類型與double&所引用的類型不同,i的底層布局從double&的角度看來是double,F中的50先被轉換為double,再存進i,存進i的內容並非int格式的50,而是浮點數格式的50,如果此時列印i的值,結果將為一個“混亂”的整數;二是由於double和int的二進位寬度不一定相同,如果double寬度大於int,則F和G都將導致未定義行為。
對於C++新增的static_cast、reinterpret_cast、const_cast三種強制轉換方式,由於C++將C風格強制轉換和函數風格強制轉換都轉換為上述三種方式,因此結果與上述例子相同。而對於dynamic_cast,若目標類型為引用,結果為左值,否則為右值。