詳解C++編程中向函數(shù)傳遞引用參數(shù)的用法
引用類(lèi)型的函數(shù)參數(shù)
向函數(shù)傳遞引用而非大型對(duì)象的效率通常更高。 這使編譯器能夠在保持已用于訪問(wèn)對(duì)象的語(yǔ)法的同時(shí)傳遞對(duì)象的地址。 請(qǐng)考慮以下使用了 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() { }
前面的代碼顯示通過(guò)引用傳遞的結(jié)構(gòu)的成員是通過(guò)成員選擇運(yùn)算符 (.) 訪問(wèn)的,而不是通過(guò)指針成員選擇運(yùn)算符 (–>) 訪問(wèn)的。
盡管作為引用類(lèi)型傳遞的參數(shù)遵循了非指針類(lèi)型的語(yǔ)法,但它們?nèi)匀槐A袅酥羔橆?lèi)型的一個(gè)重要特征:除非被聲明為 const,否則它們是可以修改的。 由于上述代碼的目的不是修改對(duì)象 GDate,因此更合適的函數(shù)原型是:
long JulianFromGregorian( const Date& GDate );
此原型將確保函數(shù) JulianFromGregorian 不會(huì)更改其參數(shù)。
任何其原型采用引用類(lèi)型的函數(shù)都能接受其所在位置的相同類(lèi)型的對(duì)象,因?yàn)榇嬖趶?typename 到 typename& 的標(biāo)準(zhǔn)轉(zhuǎn)換。
引用類(lèi)型函數(shù)返回
可將函數(shù)聲明為返回引用類(lèi)型。 做出此類(lèi)聲明原因有:
- 返回的信息是一個(gè)返回引用比返回副本更有效的足夠大的對(duì)象。
- 函數(shù)的類(lèi)型必須為左值。
- 引用的對(duì)象在函數(shù)返回時(shí)不會(huì)超出范圍。
就像通過(guò)引用傳遞大型對(duì)象 to 函數(shù)或返回大型對(duì)象 from 函數(shù)可能更有效。 引用返回協(xié)議使得不必在返回前將對(duì)象復(fù)制到臨時(shí)位置。
當(dāng)函數(shù)的計(jì)算結(jié)果必須為左值時(shí),引用返回類(lèi)型也可能很有用。 大多數(shù)重載運(yùn)算符屬于此類(lèi)別,尤其是賦值運(yùn)算符。 重載運(yùn)算符在重載運(yùn)算符中有述。
示例
請(qǐng)考慮 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
請(qǐng)注意,函數(shù)x 和 y 被聲明為返回引用類(lèi)型。 這些函數(shù)可在賦值語(yǔ)句的每一端上使用。
另請(qǐng)注意在 main 中,ThePoint 對(duì)象停留在范圍中,因此其引用成員仍處于活動(dòng)狀態(tài),可以安全地訪問(wèn)。
除以下情況之外,引用類(lèi)型的聲明必須包含初始值設(shè)定項(xiàng):
- 顯式 extern 聲明
- 類(lèi)成員的聲明
- 類(lèi)中的聲明
- 函數(shù)的參數(shù)或函數(shù)的返回類(lèi)型的聲明
返回局部變量地址時(shí)的注意事項(xiàng)
如果在局部范圍中聲明某個(gè)對(duì)象,則該對(duì)象會(huì)在函數(shù)返回時(shí)銷(xiāo)毀。 如果函數(shù)返回對(duì)該對(duì)象的引用,則當(dāng)調(diào)用方嘗試使用 null 引用時(shí),該引用可能會(huì)在運(yùn)行時(shí)導(dǎo)致訪問(wèn)沖突。
// C4172 means Don't do this!!! Foo& GetFoo() { Foo f; ... return f; } // f is destroyed here
編譯器會(huì)在這種情況下發(fā)出警告:警告 C4172: 返回局部變量或臨時(shí)變量的地址。 在簡(jiǎn)單程序中,如果調(diào)用方在覆蓋內(nèi)存位置之前訪問(wèn)引用,則有時(shí)可能不會(huì)發(fā)生訪問(wèn)沖突。 這純屬運(yùn)氣。 請(qǐng)注意該警告。
對(duì)指針的引用
聲明對(duì)指針的引用的方式與聲明對(duì)對(duì)象的引用差不多。聲明對(duì)指針的引用將生成一個(gè)可像常規(guī)指針一樣使用的可修改值。
以下代碼示例演示了使用指向指針的指針與使用對(duì)指針的引用之間的差異。
函數(shù) Add1 和 Add2 在功能上是等效的(雖然它們的調(diào)用方式不同)。二者的差異在于,Add1 使用雙間接尋址,而 Add2 利用了對(duì)指針的引用的便利性。
// 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 使用對(duì)指針的引用。輸入來(lái)自 stdin。
相關(guān)文章
深入分析C++中兩個(gè)大數(shù)相乘結(jié)果不正確的問(wèn)題
本篇文章是對(duì)C++中兩個(gè)大數(shù)相乘結(jié)果不正確的問(wèn)題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C++計(jì)算任意兩個(gè)日期天數(shù)差的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何利用C++實(shí)現(xiàn)任意兩個(gè)日期天數(shù)差,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下2024-02-02利用C語(yǔ)言編寫(xiě)一個(gè)無(wú)限循環(huán)語(yǔ)句
這篇文章主要介紹了利用C語(yǔ)言編寫(xiě)一個(gè)無(wú)限循環(huán)語(yǔ)句問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11c++連接mysql5.6的出錯(cuò)問(wèn)題總結(jié)
下面小編就為大家?guī)?lái)一篇c++連接mysql5.6的出錯(cuò)問(wèn)題總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,祝大家游戲愉快哦2016-12-12C語(yǔ)言數(shù)據(jù)類(lèi)型和格式說(shuō)明符基礎(chǔ)教程示例
這篇文章主要為大家介紹了C語(yǔ)言數(shù)據(jù)類(lèi)型和格式說(shuō)明符基礎(chǔ)教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12C語(yǔ)言修煉之路悟徹?cái)?shù)組真妙理?巧用下標(biāo)破萬(wàn)敵上篇
在C語(yǔ)言和C++等語(yǔ)言中,數(shù)組元素全為指針變量的數(shù)組稱(chēng)為指針數(shù)組,指針數(shù)組中的元素都必須具有相同的存儲(chǔ)類(lèi)型、指向相同數(shù)據(jù)類(lèi)型的指針變量。指針數(shù)組比較適合用來(lái)指向若干個(gè)字符串,使字符串處理更加方便、靈活2022-02-02C語(yǔ)言模擬實(shí)現(xiàn)C++的繼承與多態(tài)示例
本篇文章主要介紹了C語(yǔ)言模擬實(shí)現(xiàn)C++的繼承與多態(tài)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05