c++ 函数的值传递,引用传递 和 引用返回的探索
2019獨角獸企業重金招聘Python工程師標準>>>
前言
C++的函數參數和返回分為按值傳遞和按引用傳遞,應用到類上面,會涉及到類的 賦值操作 復制函數 構造函數 析構函數
雖然java開發了兩年,但對我而言c++我還只是一個初學者.c++還有很多陌生的特性需要自己親自探索.這里用實際例子作為探索,不對之處望斧正:
由于基本類型和類在函數里的生命周期是相似的,這里以一個自定義類為例,一是為了方便觀察對象的地址,二是可以了解每一步會涉及到類的哪些生命周期:
類的定義
#include <iostream>using std::cout; using std::endl; using std::string;class A { public:A() {cout << "構造函數:" << this << endl;}A(const A &input) {cout << "復制函數:" << this << endl;}// 復制直接返回 *this 本身A &operator=(const A &input) {cout << "賦值函數:" << this << endl;// this 其實是個新的內存空間,啥值都沒設置return *this;}~A() {cout << "析構函數:" << this << endl;} };值傳遞 和 返回值
我們定義一個值傳遞的函數,返回的也是值
A test1(A a) {cout << "test1函數體:&a=" << &a << endl;return a; }執行main函數如下
int main() {cout << "--- 對象創建 ---" << endl;A a;cout << "--- 函數調用 ---" << endl;A b = test1(a);cout << "--- 結束 ---" << endl;return 0; }執行結果
--- 對象創建 --- 構造函數:0x7fff5ed19768 --- 函數調用 --- 復制函數:0x7fff5ed19750 test1函數體:&a=0x7fff5ed19750 復制函數:0x7fff5ed19758 析構函數:0x7fff5ed19750 --- 結束 --- 析構函數:0x7fff5ed19758 析構函數:0x7fff5ed19768由此可見,在函數的棧幀里,對入參a進行了一次復制(0x7fff5ed19750),而在返回棧幀里的input時,又會對函數結果復制生成一個臨時變量(0x7fff5ed19758),并回收棧幀里的input. 函數結束會把臨時變量返回給b,至此結束函數調用.也就是說,這里函數的入參和返回各涉及一次復制操作
函數入參和返回使用引用
我們對test1做出修改,將入參和返回變更為引用,如下
A &test1(A &a) {cout << "test1函數體:&a=" << &a << endl;return a; }將main中的b也變更為引用如下:
int main() {cout << "--- 對象創建 ---" << endl;A a;cout << "--- 函數調用 ---" << endl;A &b = test1(a);cout << "--- 結束 ---" << endl;return 0; }執行結果:
--- 對象創建 --- 構造函數:0x7fff56dd5768 --- 函數調用 --- test1函數體:&a=0x7fff56dd5768 --- 結束 --- 析構函數:0x7fff56dd5768因為是引用函數棧幀內并沒有進行任何復制操作
函數返回的臨時變量探索
如果函數不返回引用,或b不是引用,仍然會產生臨時變量
A test1(A &a) {cout << "test1函數體:&a=" << &a << endl;return a; } A& test2(A &a) {cout << "test2函數體:&a=" << &a << endl;return a; } int main() {cout << "--- 對象創建 ---" << endl;A a;cout << "--- 函數調用1 ---" << endl;A b1 = test1(a);cout << "--- 函數調用2 ---" << endl;A b2 = test2(a);cout << "--- 結束 ---" << endl;return 0; }返回結果如下
--- 對象創建 --- 構造函數:0x7fff5daae758 --- 函數調用1 --- test1函數體:&a=0x7fff5daae758 復制函數:0x7fff5daae748 --- 函數調用2 --- test2函數體:&a=0x7fff5daae758 復制函數:0x7fff5daae740 --- 結束 --- 析構函數:0x7fff5daae740 析構函數:0x7fff5daae748 析構函數:0x7fff5daae758test1和test2的區別只在于返回結果是否為引用,但在棧幀外都產生了臨時變量
賦值操作探索
這里再對賦值做探索,這次把以上3中情況合在一起為例,如下
A &test1(A &a) {cout << "test1函數體:&a=" << &a << endl;return a; } A &test2(A a) {cout << "test2函數體:&a=" << &a << endl;return a; } A test3(A a) {cout << "test2函數體:&a=" << &a << endl;return a; } int main() {cout << "--- 對象創建 ---" << endl;A a;cout << "--- 函數調用1 ---" << endl;a = test1(a);cout << "--- 函數調用2 ---" << endl;a = test2(a);cout << "--- 函數調用3 ---" << endl;a = test3(a);cout << "--- 結束 ---" << endl;return 0; }輸出結果
--- 對象創建 --- 構造函數:0x7fff513b6748 --- 函數調用1 --- test1函數體:&a=0x7fff513b6748 賦值函數:0x7fff513b6748 --- 函數調用2 --- 復制函數:0x7fff513b6738 test2函數體:&a=0x7fff513b6738 賦值函數:0x7fff513b6748 析構函數:0x7fff513b6738 --- 函數調用3 --- 復制函數:0x7fff513b6728 test2函數體:&a=0x7fff513b6728 復制函數:0x7fff513b6730 賦值函數:0x7fff513b6748 析構函數:0x7fff513b6730 析構函數:0x7fff513b6728 --- 結束 --- 析構函數:0x7fff513b6748- test1 相當于a=a;除了將值賦值給自己外棧幀沒有額外操作,這個很好理解
- test2 對入參進行復制,并把復制的入參值賦值給a并在函數棧幀結束后回收入參
- test3 比較復雜,會復制入參和臨時變量,并把臨時變量賦值給a,賦值結束后對入參和臨時變量進行回收
轉載于:https://my.oschina.net/tdONEmadao/blog/915677
總結
以上是生活随笔為你收集整理的c++ 函数的值传递,引用传递 和 引用返回的探索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 调查显示企业对 Linux 开发人才需求
- 下一篇: 【发现问题】IDEA设置全局新创建文件默