詳解C++編程中向函數(shù)傳遞引用參數(shù)的用法
引用類型的函數(shù)參數(shù)
向函數(shù)傳遞引用而非大型對象的效率通常更高。 這使編譯器能夠在保持已用于訪問對象的語法的同時傳遞對象的地址。 請考慮以下使用了 Date 結(jié)構(gòu)的示例:
// reference_type_function_arguments.cpp
struct Date
{
short DayOfWeek;
short Month;
short Day;
short Year;
};
// Create a Julian date of the form DDDYYYY
// from a Gregorian date.
long JulianFromGregorian( Date& GDate )
{
static int cDaysInMonth[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
long JDate = 0;
// Add in days for months already elapsed.
for ( int i = 0; i < GDate.Month - 1; ++i )
JDate += cDaysInMonth[i];
// Add in days for this month.
JDate += GDate.Day;
// Check for leap year.
if ( GDate.Year % 100 != 0 && GDate.Year % 4 == 0 )
JDate++;
// Add in year.
JDate *= 10000;
JDate += GDate.Year;
return JDate;
}
int main()
{
}
前面的代碼顯示通過引用傳遞的結(jié)構(gòu)的成員是通過成員選擇運算符 (.) 訪問的,而不是通過指針成員選擇運算符 (–>) 訪問的。
盡管作為引用類型傳遞的參數(shù)遵循了非指針類型的語法,但它們?nèi)匀槐A袅酥羔橆愋偷囊粋€重要特征:除非被聲明為 const,否則它們是可以修改的。 由于上述代碼的目的不是修改對象 GDate,因此更合適的函數(shù)原型是:
long JulianFromGregorian( const Date& GDate );
此原型將確保函數(shù) JulianFromGregorian 不會更改其參數(shù)。
任何其原型采用引用類型的函數(shù)都能接受其所在位置的相同類型的對象,因為存在從 typename 到 typename& 的標準轉(zhuǎn)換。
引用類型函數(shù)返回
可將函數(shù)聲明為返回引用類型。 做出此類聲明原因有:
- 返回的信息是一個返回引用比返回副本更有效的足夠大的對象。
- 函數(shù)的類型必須為左值。
- 引用的對象在函數(shù)返回時不會超出范圍。
就像通過引用傳遞大型對象 to 函數(shù)或返回大型對象 from 函數(shù)可能更有效。 引用返回協(xié)議使得不必在返回前將對象復(fù)制到臨時位置。
當(dāng)函數(shù)的計算結(jié)果必須為左值時,引用返回類型也可能很有用。 大多數(shù)重載運算符屬于此類別,尤其是賦值運算符。 重載運算符在重載運算符中有述。
示例
請考慮 Point 示例:
// refType_function_returns.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Point
{
public:
// Define "accessor" functions as
// reference types.
unsigned& x();
unsigned& y();
private:
// Note that these are declared at class scope:
unsigned obj_x;
unsigned obj_y;
};
unsigned& Point :: x()
{
return obj_x;
}
unsigned& Point :: y()
{
return obj_y;
}
int main()
{
Point ThePoint;
// Use x() and y() as l-values.
ThePoint.x() = 7;
ThePoint.y() = 9;
// Use x() and y() as r-values.
cout << "x = " << ThePoint.x() << "\n"
<< "y = " << ThePoint.y() << "\n";
}
輸出
x = 7 y = 9
請注意,函數(shù)x 和 y 被聲明為返回引用類型。 這些函數(shù)可在賦值語句的每一端上使用。
另請注意在 main 中,ThePoint 對象停留在范圍中,因此其引用成員仍處于活動狀態(tài),可以安全地訪問。
除以下情況之外,引用類型的聲明必須包含初始值設(shè)定項:
- 顯式 extern 聲明
- 類成員的聲明
- 類中的聲明
- 函數(shù)的參數(shù)或函數(shù)的返回類型的聲明
返回局部變量地址時的注意事項
如果在局部范圍中聲明某個對象,則該對象會在函數(shù)返回時銷毀。 如果函數(shù)返回對該對象的引用,則當(dāng)調(diào)用方嘗試使用 null 引用時,該引用可能會在運行時導(dǎo)致訪問沖突。
// C4172 means Don't do this!!!
Foo& GetFoo()
{
Foo f;
...
return f;
} // f is destroyed here
編譯器會在這種情況下發(fā)出警告:警告 C4172: 返回局部變量或臨時變量的地址。 在簡單程序中,如果調(diào)用方在覆蓋內(nèi)存位置之前訪問引用,則有時可能不會發(fā)生訪問沖突。 這純屬運氣。 請注意該警告。
對指針的引用
聲明對指針的引用的方式與聲明對對象的引用差不多。聲明對指針的引用將生成一個可像常規(guī)指針一樣使用的可修改值。
以下代碼示例演示了使用指向指針的指針與使用對指針的引用之間的差異。
函數(shù) Add1 和 Add2 在功能上是等效的(雖然它們的調(diào)用方式不同)。二者的差異在于,Add1 使用雙間接尋址,而 Add2 利用了對指針的引用的便利性。
// references_to_pointers.cpp
// compile with: /EHsc
#include <iostream>
#include <string>
// STL namespace
using namespace std;
enum {
sizeOfBuffer = 132
};
// Define a binary tree structure.
struct BTree {
char *szText;
BTree *Left;
BTree *Right;
};
// Define a pointer to the root of the tree.
BTree *btRoot = 0;
int Add1( BTree **Root, char *szToAdd );
int Add2( BTree*& Root, char *szToAdd );
void PrintTree( BTree* btRoot );
int main( int argc, char *argv[] ) {
// Usage message
if( argc < 2 ) {
cerr << "Usage: Refptr [1 | 2]" << "\n";
cerr << "\nwhere:\n";
cerr << "1 uses double indirection\n";
cerr << "2 uses a reference to a pointer.\n";
cerr << "\nInput is from stdin.\n";
return 1;
}
char *szBuf = new char[sizeOfBuffer];
if (szBuf == NULL) {
cerr << "Out of memory!\n";
return -1;
}
// Read a text file from the standard input device and
// build a binary tree.
//while( !cin.eof() )
{
cin.get( szBuf, sizeOfBuffer, '\n' );
cin.get();
if ( strlen( szBuf ) ) {
switch ( *argv[1] ) {
// Method 1: Use double indirection.
case '1':
Add1( &btRoot, szBuf );
break;
// Method 2: Use reference to a pointer.
case '2':
Add2( btRoot, szBuf );
break;
default:
cerr << "Illegal value '"
<< *argv[1]
<< "' supplied for add method.\n"
<< "Choose 1 or 2.\n";
return -1;
}
}
}
// Display the sorted list.
PrintTree( btRoot );
}
// PrintTree: Display the binary tree in order.
void PrintTree( BTree* MybtRoot ) {
// Traverse the left branch of the tree recursively.
if ( btRoot->Left )
PrintTree( btRoot->Left );
// Print the current node.
cout << btRoot->szText << "\n";
// Traverse the right branch of the tree recursively.
if ( btRoot->Right )
PrintTree( btRoot->Right );
}
// Add1: Add a node to the binary tree.
// Uses double indirection.
int Add1( BTree **Root, char *szToAdd ) {
if ( (*Root) == 0 ) {
(*Root) = new BTree;
(*Root)->Left = 0;
(*Root)->Right = 0;
(*Root)->szText = new char[strlen( szToAdd ) + 1];
strcpy_s((*Root)->szText, (strlen( szToAdd ) + 1), szToAdd );
return 1;
}
else {
if ( strcmp( (*Root)->szText, szToAdd ) > 0 )
return Add1( &((*Root)->Left), szToAdd );
else
return Add1( &((*Root)->Right), szToAdd );
}
}
// Add2: Add a node to the binary tree.
// Uses reference to pointer
int Add2( BTree*& Root, char *szToAdd ) {
if ( Root == 0 ) {
Root = new BTree;
Root->Left = 0;
Root->Right = 0;
Root->szText = new char[strlen( szToAdd ) + 1];
strcpy_s( Root->szText, (strlen( szToAdd ) + 1), szToAdd );
return 1;
}
else {
if ( strcmp( Root->szText, szToAdd ) > 0 )
return Add2( Root->Left, szToAdd );
else
return Add2( Root->Right, szToAdd );
}
}
用法:Refptr [1 | 2]
其中:
1 使用雙間接尋址
2 使用對指針的引用。輸入來自 stdin。
相關(guān)文章
C++實現(xiàn)LeetCode(65.驗證數(shù)字)
這篇文章主要介紹了C++實現(xiàn)LeetCode(65.驗證數(shù)字),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07
C語言入門篇--學(xué)習(xí)選擇,if,switch語句以及代碼塊
本篇文章是基礎(chǔ)篇,適合c語言剛?cè)腴T的朋友,本文主要帶大家學(xué)習(xí)一下C語言的選擇,if,switch語句及代碼塊,幫助大家快速入門c語言的世界,更好的理解c語言2021-08-08
C語言詳細圖解浮點型數(shù)據(jù)的存儲實現(xiàn)
使用編程語言進行編程時,需要用到各種變量來存儲各種信息。變量保留的是它所存儲的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個變量時,就會在內(nèi)存中保留一些空間。您可能需要存儲各種數(shù)據(jù)類型的信息,操作系統(tǒng)會根據(jù)變量的數(shù)據(jù)類型,來分配內(nèi)存和決定在保留內(nèi)存中存儲什么2022-05-05
使用c++調(diào)用windows打印api進行打印的示例代碼
這篇文章主要介紹了使用c++調(diào)用windows打印api進行打印的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06

