第12章 創建參考
12.1什么是參考
參考是一個別名,創建參考時,使用另一個物件(目標)的名稱來初始化它,從此以后該參考就像是目標的另一個名稱,對參考執行的任何操作實際上針對的就是目標,
有些書上說參考就是指標,這不正確,雖然參考常常是使用指標實作的,但是只有編譯器開發人員關心這一點,作為程式員,必須區分這兩種概念,
指標是存盤另一個物件的地址的變數,而參考時物件的別名,
12.2創建參考
要創建參考,需要指定目標物件的型別、參考運算子(&)和參考名,
程式清單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;
}

12.3將地址運算子用于參考
如果請求回傳參考的地址,就將回傳它指向的目標的地址,這是參考的特征:他們是目標的別名,
程式清單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;
}

通常,使用參考時,不將地址運算子用于它,而像使用目標變數那樣使用參考,
程式清單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;
}

12.4可參考的目標
因為物件也是一種變數,所以可參考任何物件,包括用戶定義的物件,可以像使用物件那樣使用物件的參考:訪問成員資料和成員函式時,使用類成員訪問運算子(.)與內置型別的參考一樣,指向物件的參考也是物件的別名,
12.5空指標和空參考
指標未初始化或被洗掉時,應將其賦為nullptr,但參考不一樣,參考不能為空,讓參考指向空物件的程式是非法的,
12.6按參考傳遞函式引數
前面知道了函式的兩個局限性:引數按值傳遞;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;
}

可見兩種方式(指標傳地址、參考傳原參)達到的效果是一樣的,但是參考傳遞中,呼叫方只需傳遞變數,且在函式內部,需要使用的特殊符號減少了,降低了程式的復雜性,參考將常規變數方便而易于使用的特點和指標的強大融為一體,
12.7理解函式頭和原型
函式原型的另一個重要用途:通過查看原型中宣告的引數(函式原型通常放在頭檔案中),程式員知道swap()的引數是按指標還是參考傳遞的,從而將正確呼叫他們,
在c++中,類的使用者(其他類中使用該類的函式)依賴于頭檔案來獲悉需要的所有資訊,頭檔案相當于類或函式的介面,而實際實作對使用者是隱藏的,這讓程式員能夠將主要精力放在要解決的問題上,而使用類或函式時無需關心它是如何實作的,
12.8回傳多個值
(哦,這說和沒說是一樣的,還是只能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;
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/1850.html
標籤:C++
下一篇:要點1:指標、陣列和復合字面量
