引用是一個別名。建立引用時,使用另外一個對象(目標)的名稱來初始化它,今後之後該引用就像是目標的另外一個名稱,對引用執行的任何操做實際上針對的就是目標。ios
有些書上說引用就是指針,這不正確。雖然引用經常是使用指針實現的,可是隻有編譯器開發人員關心這一點,做爲程序員,必須區分這兩種概念。c++
指針是存儲另外一個對象的地址的變量,而引用時對象的別名。程序員
要建立引用,須要指定目標對象的類型、引用運算符(&)和引用名。函數
程序清單12.1 Reference.cpp指針
#include <iostream> int main() { int intOne; int &rSomeRef = intOne; intOne = 5; std::cout << "intOne: " << intOne << std::endl; std::cout << "rSomeRef: " << rSomeRef << std::endl; rSomeRef = 7; std::cout << "intOne: " << intOne << std::endl; std::cout << "rSomeRef: " << rSomeRef << std::endl; return 0; }
若是請求返回引用的地址,就將返回它指向的目標的地址。這是引用的特徵:他們是目標的別名。code
程序清單12.2 Reference2.cpp對象
#include <iostream> int main() { int intOne; int &rSomeRef = intOne; intOne = 5; std::cout << "intOne: " << intOne << std::endl; std::cout << "rSomeRef: " << rSomeRef << std::endl; std::cout << "&intOne: " << &intOne << std::endl; std::cout << "&rSomeRef: " << &rSomeRef << std::endl; return 0; }
一般,使用引用時,不將地址運算符用於它,而像使用目標變量那樣使用引用。blog
程序清單12.3 Assignment.cpp接口
#include <iostream> int main() { int intOne; int &rSomeRef = intOne; intOne = 5; std::cout << "intOne:\t" << intOne << std::endl; std::cout << "rSomeRef:\t" << rSomeRef << std::endl; std::cout << "&intOne:\t" << &intOne << std::endl; std::cout << "&rSomeRef:\t" << &rSomeRef << std::endl; int intTwo = 8; rSomeRef = intTwo; std::cout << "\nintOne:\t" << intOne << std::endl; std::cout << "intTwo:\t" << intTwo << std::endl; std::cout << "rSomeRef:\t" << rSomeRef << std::endl; std::cout << "&intOne:\t" << &intOne << std::endl; std::cout << "&intTwo:\t" << &intTwo << std::endl; std::cout << "&rSomeRef:\t" << &rSomeRef << std::endl; return 0; }
由於對象也是一種變量,因此可引用任何對象,包括用戶定義的對象。能夠像使用對象那樣使用對象的引用:訪問成員數據和成員函數時,使用類成員訪問運算符(.)與內置類型的引用同樣,指向對象的引用也是對象的別名。ci
指針未初始化或被刪除時,應將其賦爲nullptr,但引用不同,引用不能爲空,讓引用指向空對象的程序是非法的。
前面知道了函數的兩個侷限性:參數按值傳遞;return語句只能返回一個值。
經過將值按引用傳遞給函數,可消除這兩種侷限性。在c++中,按引用傳遞時經過兩種方式完成的:使用指針和使用引用。他們的語法不一樣,但效果相同:不是在函數做用域內建立備份(也就是否是值拷貝),而是將原始對象傳遞給函數。
程序清單12.4 ValuePasser.cpp
#include <iostream> void swap(int x, int y); int main() { int x = 5, y = 10; std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl; swap(x, y); std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl; return 0; } void swap(int x, int y) { int temp; std::cout << "Swap. Before swap,x: " << x << " y: " << y << std::endl; temp = x; x = y; y = temp; std::cout << "Swap. After swap,x: " << x << " y: " << y << std::endl; }
main()中的值都沒變,可見值拷貝並不能改變原參的值
使用指針實現swap()
程序清單12.5 PointerSwap.cpp
#include <iostream> void swap(int *x, int *y); int main() { int x = 5, y = 10; std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl; swap(&x, &y);//將地址做爲參數傳遞 std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl; return 0; } void swap(int *px, int *py)//參數聲明爲指針 { int temp; std::cout << "Swap. Before swap,*px: " << *px << " *py: " << *py << std::endl; temp = *px; *px = *py; *py = temp; std::cout << "Swap. After swap,*px: " << *px << " *py: " << *py << std::endl; }
使用引用實現swap()
c++的目標之一時,避免函數的調用者操心函數的工做原理,而將注意力放在函數的功能和返回值上。傳遞指針將負擔轉嫁給了調用方,而這種負擔本來不該該由調用方來承擔:調用方必須知道將要交換的對象的地址傳入。
明白引用語法的負擔應由函數的實現方承擔。爲此,可以使用引用。
程序清單12.6 ReferenceSwap.cpp
#include <iostream> void swap(int &x, int &y); int main() { int x = 5, y = 10; std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl; swap(x, y); std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl; return 0; } void swap(int &rx, int &ry)//參數聲明爲引用 { int temp; std::cout << "Swap. Before swap,rx: " << rx << " ry: " << ry << std::endl; temp = rx; rx = ry; ry = temp; std::cout << "Swap. After swap,rx: " << rx << " ry: " << ry << std::endl; }
可見兩種方式(指針傳地址、引用傳原參)達到的效果是同樣的,可是引用傳遞中,調用方只需傳遞變量,且在函數內部,須要使用的特殊符號減小了,下降了程序的複雜性。引用將常規變量方便而易於使用的特色和指針的強大融爲一體。
函數原型的另外一個重要用途:經過查看原型中聲明的參數(函數原型一般放在頭文件中),程序員知道swap()的參數是按指針仍是引用傳遞的,從而將正確調用他們。
在c++中,類的使用者(其餘類中使用該類的函數)依賴於頭文件來獲悉須要的全部信息。頭文件至關於類或函數的接口,而實際實現對使用者是隱藏的。這讓程序員可以將主要精力放在要解決的問題上,而使用類或函數時無需關心它是如何實現的。
(哦,這說和沒說是同樣的,仍是隻能return一個東西)
一種解決辦法是將多個對象按引用傳入函數,而後在函數中將正確的值賦給這些對象。因爲按引用傳遞讓函數可以修改原始對象,所以這至關於讓函數可以返回多項信息。這種函數未使用函數的返回值,可將其(指返回值)用於報告錯誤。
另外一種辦法是使用指針或引用來實現。
程序清單12.7 ReturnPointer.cpp
#include <iostream> short factor(int, int *, int *); int main() { int number, squared, cubed; short error; std::cout << "Enter a number(0 - 20): "; std::cin >> number; error = factor(number, &squared, &cubed); if (!error) { std::cout << "number: " << number << "\n"; std::cout << "square: " << squared << "\n"; std::cout << "cubed: " << cubed << "\n"; } else std::cout << "Error encountered!!\n"; return 0; } short factor(int n, int *pSquared, int *pCubed) { short vaule = 0; if (n > 20) { vaule = 1; } else { *pSquared = n * n; *pCubed = n * n * n; vaule = 0; } return vaule; }
按引用返回值
雖然程序ReturnPointer.cpp可行,可是若是使用引用而不是指針,將更容易理解和維護。
程序清單12.8 ReturnReference.cpp
#include <iostream> enum ERR_CODE//枚舉 { SUCCESS, ERROR }; ERR_CODE factor(int, int &, int &); int main() { int number, squared, cubed; ERR_CODE result; std::cout << "Enter a number(0 - 20): "; std::cin >> number; result = factor(number, squared, cubed); if (result == SUCCESS) { std::cout << "number: " << number << "\n"; std::cout << "square: " << squared << "\n"; std::cout << "cubed: " << cubed << "\n"; } else std::cout << "Error encountered!!\n"; return 0; } ERR_CODE factor(int n, int &pSquared, int &pCubed) { short vaule = 0; if (n > 20) { return ERROR; } else { pSquared = n * n; pCubed = n * n * n; return SUCCESS; } }