一、變量的本質(zhì) - 引入 " 引用 " 概念
" 引用 " 語(yǔ)法 是 C++ 語(yǔ)言中 特有的 , 在 C 語(yǔ)言中是沒(méi)有 引用 這個(gè)概念的 ;
1、變量的本質(zhì) - 內(nèi)存別名
分析 引用 之前 , 先回顧下 變量 :
在 【C 語(yǔ)言】變量本質(zhì) ( 變量概念 | 變量本質(zhì) - 內(nèi)存空間別名 | 變量存儲(chǔ)位置 - 代碼區(qū) | 變量三要素 ) 博客中 , 介紹了變量的本質(zhì) :
變量 的本質(zhì)是 內(nèi)存空間 的 " 別名 " , 簡(jiǎn)稱(chēng) " 內(nèi)存別名 " , 相當(dāng)于 " 門(mén)牌號(hào) " ;
C 語(yǔ)言 / C++ 語(yǔ)言 的 程序 , 通過(guò) 變量 來(lái)申請(qǐng) 內(nèi)存空間 , 并為該 內(nèi)存空間 命名 , 名稱(chēng)就是變量名 ;
下面的代碼中 , 定義變量 a , 就是在 棧內(nèi)存 中申請(qǐng)了 4 字節(jié)內(nèi)存 , 這 4 字節(jié)連續(xù)內(nèi)存的別名是 a , 為該變量賦值 10 , 就是將 10 存儲(chǔ)到 4 字節(jié)內(nèi)存中 ;
int a = 10;
通過(guò) " 變量名稱(chēng) " 可以使用 變量名 代表的 連續(xù)內(nèi)存空間 , 之后使用變量 a 進(jìn)行計(jì)算 , 就是 使用 變量 a 表示的 4 字節(jié)內(nèi)存中的數(shù)據(jù)進(jìn)行計(jì)算 ;
2、引入 " 引用 " 概念 - 已定義變量的內(nèi)存別名
下面討論下 , 上述 變量 a 是 4 字節(jié)連續(xù)內(nèi)存空間的別名 , 那么 這段 4 字節(jié)的內(nèi)存空間 只能有一個(gè)內(nèi)存別名嗎 ? 還是可以有多個(gè)內(nèi)存別名 ?
答案是可以的 , 如果想要為 上述 4 字節(jié)內(nèi)存空間再次 賦予 一個(gè) " 內(nèi)存別名 " , 就需要使用 " 引用 " 了 ;
" 引用 " 就是 已定義 變量 的 內(nèi)存別名 ;
- 第一次為 一塊內(nèi)存 賦予 別名 , 是 定義變量 的時(shí)候 ;
- 第二次再為 該內(nèi)存 賦予 別名 , 就是 獲取該變量的 " 引用 " ;
3、" 引用 " 的優(yōu)點(diǎn)
C++ 語(yǔ)言中的 引用 是特殊的變量 , 通過(guò)引用可以訪問(wèn)已經(jīng)存在的變量 ;
使用 " 引用 " 的優(yōu)點(diǎn) :
- 提高訪問(wèn)效率 : 向 函數(shù) 傳遞參數(shù)時(shí) , 使用引用可以減少消耗 , 類(lèi)似于傳入指針 , 如果傳入一個(gè)較大的數(shù)組 , 需要拷貝整個(gè)數(shù)組作為變量副本 , 拷貝會(huì)消耗很多性能 ;
- 提高代碼可讀性 : 引用使用時(shí) , 類(lèi)似于 一級(jí)指針 , 使用引用期間 , 不需要 使用 取地址符 & 和 指針?lè)?hào) * , 提高了代碼可讀性 和 可維護(hù)性 ;
- 函數(shù)返回值 : 函數(shù)引用參數(shù) 可以作為 返回值使用 ;
二、引用語(yǔ)法簡(jiǎn)介
1、語(yǔ)法說(shuō)明
" 引用 " 語(yǔ)法如下 :
類(lèi)型& 引用名稱(chēng) = 變量;
& 符號(hào)建議緊貼類(lèi)型寫(xiě) , 與 引用名稱(chēng) 使用空格隔開(kāi) ;
( 指針?lè)?hào) * 建議也是緊貼 指針類(lèi)型 , 與指針名稱(chēng)使用空格隔開(kāi) , 如 : int* p = NULL;
)
引用 定義后 , 可以當(dāng)做變量使用 ;
通過(guò)引用 , 可以操作變量 , 訪問(wèn) , 修改 引用 , 變量也會(huì)進(jìn)行相應(yīng)修改 ;
使用引用作為函數(shù)參數(shù)時(shí) ,
- 傳入的實(shí)參不需要使用取地址符獲取 , 直接將變量傳入函數(shù)即可 ;
- 在函數(shù)中 訪問(wèn)引用 時(shí) , 不需要使用指針 , 直接使用引用訪問(wèn)傳入的變量 ;
代碼示例 :
// 定義變量 a , 變量本質(zhì)是內(nèi)存別名
int a = 10;
// 定義引用 b , 是變量 a 的別名
int& b = a;
// 通過(guò)引用修改變量的值
b = 100;
引用是 C++ 的概念 , 在 C 語(yǔ)言中不能使用引用 ;
上述代碼在 C 語(yǔ)言中實(shí)現(xiàn) 是完全不同的 , 下面是 上述代碼在 C 語(yǔ)言中的實(shí)現(xiàn) :
// 定義變量 a , 變量本質(zhì)是內(nèi)存別名
int a = 10;
// 獲取 變量 a 的地址 , 賦值給 指針常量 b
// 指針常量 是 常量 - 指針本身不能修改 , 常量指針 是 指針 - 指向常量的指針
// 左數(shù)右指 , const 在 指針 * 的右邊 , 指針 是常量 , 指針的指向不能更改
int* const b = &a;
// 通過(guò) 指針常量 修改 指針指向的內(nèi)存空間的值
// 指針指向不能修改 , 指向的內(nèi)存中的內(nèi)容可以修改
*b = 100;
在上述代碼中 ,
- 首先 , 獲取 變量 a 的地址 , 賦值給 指針常量 b ;
- 指針常量 是 常量 - 指針本身不能修改 ;
- 常量指針 是 指針 - 指向常量的指針 ;
- 左數(shù)右指 , const 在 指針 * 的右邊 , 指針 是常量 , 指針的指向不能更改 ;
- 然后 , 通過(guò) 指針常量 修改 指針指向的內(nèi)存空間的值 ;
- 指針指向的地址不能修改 ;
- 指針指向的內(nèi)存中的內(nèi)容可以修改 ;
2、代碼示例 - 引用的定義和使用
下面的代碼中 , 引用 b 是 變量 a 的別名 , 通過(guò) 引用 b 可以訪問(wèn) 變量 a 的內(nèi)存空間 ;
代碼中同時(shí)打印 引用 b 和 變量 a , 都可以打印出 變量值 10 ;
修改 引用 b 的值 , 變量 a 的值也會(huì)被修改 ;
代碼示例 :
// 包含 C++ 頭文件
#include "iostream"
// 使用 std 標(biāo)準(zhǔn)命名空間
// 該命名空間中 , 定義了很多標(biāo)準(zhǔn)定義
using namespace std;
// 導(dǎo)入 C 頭文件
#include <stdio.h>
int main()
{
// 定義變量 a , 變量本質(zhì)是內(nèi)存別名
int a = 10;
// 定義引用 b , 是變量 a 的別名
int& b = a;
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 通過(guò)引用修改變量值
b = 100;
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 控制臺(tái)暫停 , 按任意鍵繼續(xù)向后執(zhí)行
//system("pause");
return 0;
}
執(zhí)行結(jié)果 :
a = 10, b = 10
a = 100, b = 100
三、引用做函數(shù)參數(shù)
1、普通引用必須初始化 - 函數(shù)參數(shù)除外
普通的引用 , 必須要依附于某個(gè)變量 , 在定義 " 引用 " 時(shí) , 必須進(jìn)行初始化 , 否則就會(huì)報(bào)如下錯(cuò)誤 :
引用 變量 x 需要初始值設(shè)定項(xiàng)
這里有一種特殊情況 , 在聲明時(shí)可以不進(jìn)行初始化 ,
" 引用 " 做 函數(shù) 形參 時(shí) , 可以不進(jìn)行初始化 ;
使用 引用 作為 函數(shù)參數(shù) , 與 一級(jí)指針 效果相同 , 并且用起來(lái)比較簡(jiǎn)單 , 不需要操作指針 ;
引用 比較符合 Java / C# 語(yǔ)言風(fēng)格 , 不需要操作繁瑣的指針 ;
定義兩個(gè)變量 :
// 定義變量 a , b , 變量本質(zhì)是內(nèi)存別名
int a = 10, b = 20;
寫(xiě)一個(gè)函數(shù) , 交換這兩個(gè)變量的值 ;
2、代碼示例 - 使用普通變量作為參數(shù) ( 無(wú)法實(shí)現(xiàn)變量交換 )
下面的代碼中 , 定義的交換函數(shù) , 傳入的形參是普通變量 ;
參數(shù)是普通變量 , 實(shí)參就是變量的副本 , 變量的作用域僅限于函數(shù)內(nèi) , 無(wú)法傳遞到函數(shù)外部 , 外部的變量無(wú)法被改變 ;
代碼示例 :
// 包含 C++ 頭文件
#include "iostream"
// 使用 std 標(biāo)準(zhǔn)命名空間
// 該命名空間中 , 定義了很多標(biāo)準(zhǔn)定義
using namespace std;
// 導(dǎo)入 C 頭文件
#include <stdio.h>
// 交換 a 和 b 的值
// 該函數(shù)無(wú)法實(shí)現(xiàn)交換 , 因?yàn)閭魅氲膶?shí)參只是副本
// 并不能真實(shí)的改變傳入的值
void swap(int a, int b)
{
int c = 0;
c = a;
a = b;
b = c;
}
int main()
{
// 定義變量 a , b , 變量本質(zhì)是內(nèi)存別名
int a = 10, b = 20;
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 傳入變量副本 : 交換 a 和 b 的值 , 交換失敗
swap(a, b);
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 控制臺(tái)暫停 , 按任意鍵繼續(xù)向后執(zhí)行
system("pause");
return 0;
}
執(zhí)行結(jié)果 :
a = 10, b = 20
a = 10, b = 20
3、代碼示例 - 使用指針變量作為參數(shù) ( C 語(yǔ)言中實(shí)現(xiàn)變量交換的方法 )
在下面的代碼中 , 使用 C 語(yǔ)言的方式實(shí)現(xiàn)了 變量交換函數(shù) ;
函數(shù)參數(shù)接收 指針變量 作為 參數(shù) , 傳入的實(shí)參是變量的地址 ;
在函數(shù)內(nèi)部 , 訪問(wèn)變量需要通過(guò) 指針 * 符號(hào)進(jìn)行 ;
這樣可以實(shí)現(xiàn) 外部變量 的數(shù)值交換 , 但是 使用 指針 * 進(jìn)行操作 , 代碼十分復(fù)雜繁瑣 , 不易理解 ;
代碼示例 :
// 包含 C++ 頭文件
#include "iostream"
// 使用 std 標(biāo)準(zhǔn)命名空間
// 該命名空間中 , 定義了很多標(biāo)準(zhǔn)定義
using namespace std;
// 導(dǎo)入 C 頭文件
#include <stdio.h>
// 交換 a 和 b 的值
// C 語(yǔ)言中可以使用該方法
void swap(int* a, int* b)
{
int c = 0;
c = *a;
*a = *b;
*b = c;
}
int main()
{
// 定義變量 a , b , 變量本質(zhì)是內(nèi)存別名
int a = 10, b = 20;
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 傳入指針地址 : 交換 a 和 b 的值 , 交換成功
swap(&a, &b);
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 控制臺(tái)暫停 , 按任意鍵繼續(xù)向后執(zhí)行
system("pause");
return 0;
}
執(zhí)行結(jié)果 :
a = 10, b = 20
a = 20, b = 10
4、代碼示例 - 使用引用作為參數(shù) ( C++ 語(yǔ)言中實(shí)現(xiàn)變量交換的方法 )
在下面的代碼中 , 使用引用作為函數(shù)參數(shù) , 也實(shí)現(xiàn)了變量交換 ;
C++ 中的引用使用非常簡(jiǎn)單 , 沒(méi)有使用指針進(jìn)行操作 ;
在使用引用時(shí) , 可以看到 引用的效果 , 實(shí)際上等同于一級(jí)指針 ;
使用引用作為函數(shù)參數(shù)時(shí) , 傳入的實(shí)參不需要使用取地址符獲取 , 直接將變量傳入函數(shù)即可 , 在函數(shù)中獲取引用的值時(shí) , 不需要使用指針 , 直接使用引用訪問(wèn)傳入的變量 ;
代碼示例 :
// 包含 C++ 頭文件
#include "iostream"
// 使用 std 標(biāo)準(zhǔn)命名空間
// 該命名空間中 , 定義了很多標(biāo)準(zhǔn)定義
using namespace std;
// 導(dǎo)入 C 頭文件
#include <stdio.h>
// 交換 a 和 b 的值
// C++ 中推薦的方法
// 使用引用作為函數(shù)參數(shù)
void swap(int& a, int& b)
{
int c = 0;
c = a;
a = b;
b = c;
}
int main()
{
// 定義變量 a , b , 變量本質(zhì)是內(nèi)存別名
int a = 10, b = 20;
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 傳入引用本 : 交換 a 和 b 的值 , 交換成功
swap(a, b);
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 控制臺(tái)暫停 , 按任意鍵繼續(xù)向后執(zhí)行
system("pause");
return 0;
}
執(zhí)行結(jié)果 :
a = 10, b = 20
a = 20, b = 10
5、代碼示例 - 完整代碼示例
完整代碼示例 :
// 包含 C++ 頭文件
#include "iostream"
// 使用 std 標(biāo)準(zhǔn)命名空間
// 該命名空間中 , 定義了很多標(biāo)準(zhǔn)定義
using namespace std;
// 導(dǎo)入 C 頭文件
#include <stdio.h>
// 交換 a 和 b 的值
// 該函數(shù)無(wú)法實(shí)現(xiàn)交換 , 因?yàn)閭魅氲膶?shí)參只是副本
// 并不能真實(shí)的改變傳入的值
void swap1(int a, int b)
{
int c = 0;
c = a;
a = b;
b = c;
}
// 交換 a 和 b 的值
// C 語(yǔ)言中可以使用該方法
void swap2(int* a, int* b)
{
int c = 0;
c = *a;
*a = *b;
*b = c;
}
// 交換 a 和 b 的值
// C++ 中推薦的方法
void swap3(int& a, int& b)
{
int c = 0;
c = a;
a = b;
b = c;
}
int main()
{
// 定義變量 a , b , 變量本質(zhì)是內(nèi)存別名
int a = 10, b = 20;
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 傳入變量副本 : 交換 a 和 b 的值 , 交換失敗
swap1(a, b);
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 傳入指針 : 交換 a 和 b 的值 , 交換成功
swap2(&a, &b);
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 傳入引用 : 交換 a 和 b 的值 , 交換成功
swap3(a, b);
// 打印 變量 a 和 引用 b 的值
printf("a = %d, b = %d\n", a, b);
// 控制臺(tái)暫停 , 按任意鍵繼續(xù)向后執(zhí)行
//system("pause");
return 0;
}
執(zhí)行結(jié)果 :
a = 10, b = 20
a = 10, b = 20
a = 20, b = 10
a = 10, b = 20
四、復(fù)雜類(lèi)型引用做函數(shù)參數(shù)
1、復(fù)雜類(lèi)型參數(shù)的三種傳遞方式
定義一個(gè)結(jié)構(gòu)體類(lèi)型 , 想要傳遞結(jié)構(gòu)體對(duì)象到函數(shù)中 , 有三種方式 ;
// 定義一個(gè)結(jié)構(gòu)體
// C++ 中結(jié)構(gòu)體就是類(lèi)
struct Student
{
char name[64];
int age;
};
在棧內(nèi)存中先創(chuàng)建該結(jié)構(gòu)體對(duì)象 , 為該對(duì)象賦值 ;
Student s;
s.age = 18;
I 、傳遞結(jié)構(gòu)體對(duì)象本身
第一種方式 , 直接傳遞結(jié)構(gòu)體對(duì)象本身 ,
- 函數(shù)傳遞 : 這種方式傳遞的是 結(jié)構(gòu)體 對(duì)象的副本 , 需要拷貝對(duì)象然后將拷貝副本作為實(shí)參傳遞給函數(shù) , 拷貝的過(guò)程非常消耗性能 ;
- 參數(shù)訪問(wèn) : 傳入的參數(shù)在函數(shù)中正常訪問(wèn) ,使用 . 訪問(wèn)結(jié)構(gòu)體成員 ;
- 參數(shù)修改 : 修改該參數(shù) , 不會(huì)影響外部結(jié)構(gòu)體對(duì)象的值 , 因?yàn)樾薷牡氖强截惡蟮母北?;
// 直接傳入結(jié)構(gòu)體類(lèi)對(duì)象本身
void printStudent1(Student s)
{
// 使用變量 , 直接使用 . 訪問(wèn)結(jié)構(gòu)體成員
cout << "printStudent1 開(kāi)始執(zhí)行 age : " << s.age << endl;
s.age = 19;
}
II 、傳遞結(jié)構(gòu)體指針
第二種方式 , 傳遞結(jié)構(gòu)體 指針 ,
- 函數(shù)傳遞 : 這種方式傳遞的是 結(jié)構(gòu)體 指針 , 實(shí)際上是指針的副本 , 幾乎不消耗性能 ;
- 參數(shù)訪問(wèn) : 傳入的 指針 參數(shù) 在函數(shù)中 使用 -> 訪問(wèn)結(jié)構(gòu)體成員 ;
- 參數(shù)修改 : 通過(guò)指針 修改該參數(shù) , 外部的結(jié)構(gòu)體對(duì)象也會(huì)被修改 ;
// 傳入結(jié)構(gòu)體類(lèi)對(duì)象指針
void printStudent2(Student* s)
{
// 通過(guò) 問(wèn)結(jié)構(gòu)體指針 訪問(wèn)成員需要使用 -> 訪問(wèn)
cout << "printStudent2 開(kāi)始執(zhí)行 age : " << s->age << endl;
s->age = 20;
}
III 、傳遞結(jié)構(gòu)體引用
第三種方式 , 傳遞結(jié)構(gòu)體 引用 ,
- 函數(shù)傳遞 : 這種方式傳遞的是 結(jié)構(gòu)體 引用 , 引用只是變量的一個(gè)別名 , 幾乎不消耗性能 ;
- 參數(shù)訪問(wèn) : 傳入的 引用 參數(shù) 在函數(shù)中 使用 . 訪問(wèn)結(jié)構(gòu)體成員 , 與變量用法一樣 ;
- 參數(shù)修改 : 通過(guò)指針 修改該參數(shù) , 外部的結(jié)構(gòu)體對(duì)象也會(huì)被修改 ;
// 傳入結(jié)構(gòu)體類(lèi)對(duì)象指針
void printStudent2(Student* s)
{
// 通過(guò) 問(wèn)結(jié)構(gòu)體指針 訪問(wèn)成員需要使用 -> 訪問(wèn)
cout << "printStudent2 開(kāi)始執(zhí)行 age : " << s->age << endl;
s->age = 20;
}
2、代碼示例 - 使用三種傳遞方式傳遞參數(shù)
代碼示例 :
// 包含 C++ 頭文件
#include "iostream"
// 使用 std 標(biāo)準(zhǔn)命名空間
// 該命名空間中 , 定義了很多標(biāo)準(zhǔn)定義
using namespace std;
// 導(dǎo)入 C 頭文件
#include <stdio.h>
// 定義一個(gè)結(jié)構(gòu)體
// C++ 中結(jié)構(gòu)體就是類(lèi)
struct Student
{
char name[64];
int age;
};
// 直接傳入結(jié)構(gòu)體類(lèi)對(duì)象本身
void printStudent1(Student s)
{
// 使用變量 , 直接使用 . 訪問(wèn)結(jié)構(gòu)體成員
cout << "printStudent1 開(kāi)始執(zhí)行 age : " << s.age << endl;
s.age = 19;
}
// 傳入結(jié)構(gòu)體類(lèi)對(duì)象指針
void printStudent2(Student* s)
{
// 通過(guò) 問(wèn)結(jié)構(gòu)體指針 訪問(wèn)成員需要使用 -> 訪問(wèn)
cout << "printStudent2 開(kāi)始執(zhí)行 age : " << s->age << endl;
s->age = 20;
}
// 傳入結(jié)構(gòu)體類(lèi)對(duì)象引用
void printStudent3(Student& s)
{
// 使用 引用 跟普通變量用法相同, 不需要使用 -> 訪問(wèn)
cout << "printStudent3 開(kāi)始執(zhí)行 age : " << s.age << endl;
s.age = 21;
}
int main()
{
Student s;
s.age = 18;
// 傳入對(duì)象 消耗性能
printStudent1(s);
cout << "printStudent1 執(zhí)行完畢 age : " << s.age << endl;
// 傳入指針 需要取地址
printStudent2(&s);
cout << "printStudent2 執(zhí)行完畢 age : " << s.age << endl;
// 傳入引用 直接傳入
printStudent3(s);
cout << "printStudent3 執(zhí)行完畢 age : " << s.age << endl;
// 控制臺(tái)暫停 , 按任意鍵繼續(xù)向后執(zhí)行
system("pause");
return 0;
}
執(zhí)行結(jié)果 :文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-672178.html
printStudent1 開(kāi)始執(zhí)行 age : 18
printStudent1 執(zhí)行完畢 age : 18
printStudent2 開(kāi)始執(zhí)行 age : 18
printStudent2 執(zhí)行完畢 age : 20
printStudent3 開(kāi)始執(zhí)行 age : 20
printStudent3 執(zhí)行完畢 age : 21
Press any key to continue . . .
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-672178.html
到了這里,關(guān)于【C++】C++ 引用詳解 ① ( 變量的本質(zhì) - 引入 “ 引用 “ 概念 | 引用語(yǔ)法簡(jiǎn)介 | 引用做函數(shù)參數(shù) | 復(fù)雜類(lèi)型引用做函數(shù)參數(shù) )的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!