C++中引用與指針的區別(詳細介紹)

轉載:http://www.cnblogs.com/tracylee/archive/2012/12/04/2801519.html

C++中的引用與指針的區別
指向不同類型的指針的區別在于指針類型可以知道編譯器解釋某個特定地址(指針指向的地址)中的內存內容及大小,而void*指針則只表示一個內存地址,編譯器不能通過該指針所指向對象的類型和大小,因此想要通過void*指針操作對象必須進行類型轉化。
?
? ??★ 相同點:
?
? ? 1. 都是地址的概念;
? ? ? ?指針指向一塊內存,它的內容是所指內存的地址;
? ? ? ?引用是某塊內存的別名。
?
? ? ★ 區別:
?
? ? 1. 指針是一個實體,而引用僅是個別名;
? ? 2. 引用使用時無需解引用(*),指針需要解引用;
? ? 3. 引用只能在定義時被初始化一次,之后不可變;指針可變;
? ? ? ?引用“從一而終” ^_^
? ? 4. 引用沒有 const,指針有 const,const 的指針不可變;
? ? 5. 引用不能為空,指針可以為空;
? ? 6.?“sizeof 引用”得到的是所指向的變量(對象)的大小,而“sizeof 指針”得到的是指針本身(所指向的變量或對象的地址)的大小;
? ? typeid(T) == typeid(T&) 恒為真,sizeof(T) == sizeof(T&) 恒為真,但是當引用作為類成員名稱時,其占用空間與指針相同4個字節(沒找到標準的規定)。
? ? 7. 指針和引用的自增(++)運算意義不一樣;
?
? ? ★ 聯系
?
? ??1. 引用在語言內部用指針實現(如何實現?)。
? ? 2. 對一般應用而言,把引用理解為指針,不會犯嚴重語義錯誤。引用是操作受限了的指針(僅容許取內容操作)。
? ? 引用是C++中的概念,初學者容易把引用和指針混淆一起。一下程序中,n 是m 的一個引用(reference),m 是被引用物(referent)。
? ? int m;
? ? int &n = m;
? ? n 相當于m 的別名(綽號),對n 的任何操作就是對m 的操作。例如有人名叫王小毛,他的綽號是“三毛”。說“三毛”怎么怎么的,其實就是對王小毛說三道四。所以n 既不是m 的拷貝,也不是指向m 的指針,其實n 就是m 它自己。
?
? ? 引用的一些規則如下:
? ? (1)引用被創建的同時必須被初始化(指針則可以在任何時候被初始化)。
? ? (2)不能有NULL 引用,引用必須與合法的存儲單元關聯(指針則可以是NULL)。
? ? (3)一旦引用被初始化,就不能改變引用的關系(指針則可以隨時改變所指的對象)。
?
? ? 以下示例程序中,k 被初始化為i 的引用。語句k = j 并不能將k 修改成為j 的引用,只是把k 的值改變成為6.由于k 是i 的引用,所以i 的值也變成了6.
?
? ? int i = 5;
? ? int j = 6;
? ? int &k = i;
? ? k = j; // k 和i 的值都變成了6;
?
?
? ? 上面的程序看起來象在玩文字游戲,沒有體現出引用的價值。引用的主要功能是傳遞函數的參數和返回值。C++語言中,函數的參數和返回值的傳遞方式有三種:值傳遞、指針傳遞和引用傳遞。
?
? ? 1)以下是“值傳遞”的示例程序。由于Func1 函數體內的x 是外部變量n 的一份拷貝,改變x 的值不會影響n, 所以n 的值仍然是0.
?
??void Func1(int x)
{
x = x + 10;
}
int n = 0;
Func1(n);
cout << “n = ” << n << endl;// n = 0

?
? ? 2)以下是“指針傳遞”的示例程序。由于Func2 函數體內的x 是指向外部變量n 的指針,改變該指針的內容將導致n 的值改變,所以n 的值成為10.
void Func2(int *x)
{
(* x) = (* x) + 10;
}
&#8943;
int n = 0;
Func2(&n);
cout << “n = ” << n << endl; // n = 10

?
? ? 3)以下是“引用傳遞”的示例程序。由于Func3 函數體內的x 是外部變量n 的引用,x和n 是同一個東西,改變x 等于改變n,所以n 的值成為10.
??void Func3(int &x)
{
x = x + 10;
}
&#8943;
int n = 0;
Func3(n);
cout << “n = ” << n << endl; // n = 10
?
? ? ?對比上述三個示例程序,會發現“引用傳遞”的性質象“指針傳遞”,而書寫方式象“值傳遞”。實際上“引用”可以做的任何事情“指針”也都能夠做,為什么還要“引用”這東西?
? ? 答案是“用適當的工具做恰如其分的工作”。
? ? 指針能夠毫無約束地操作內存中的如何東西,盡管指針功能強大,但是非常危險。
? ? 就象一把刀,它可以用來砍樹、裁紙、修指甲、理發等等,誰敢這樣用?
? ? 如果的確只需要借用一下某個對象的“別名”,那么就用“引用”,而不要用“指針”,以免發生意外。比如說,某人需要一份證明,本來在文件上蓋上公章的印子就行了,如果把取公章的鑰匙交給他,那么他就獲得了不該有的權利。
?
? ? ——————————
?
? ? 摘自「高質量c++編程」
?
? ? 指針與引用,在More Effective C++ 的條款一有詳細講述,我給你轉過來
?
? ? 條款一:指針與引用的區別
?
? ? 指針與引用看上去完全不同(指針用操作符‘*’和‘->’,引用使用操作符‘。’),但是它們似乎有相同的功能。指針與引用都是讓你間接引用其他對象。你如何決定在什么時候使用指針,在什么時候使用引用呢?
? ? 首先,要認識到在任何情況下都不能用指向空值的引用。一個引用必須總是指向某些對象。因此如果你使用一個變量并讓它指向一個對象,但是該變量在某些時候也可能不指向任何對象,這時你應該把變量聲明為指針,因為這樣你可以賦空值給該變量。相反,如果變量肯定指向一個對象,例如你的設計不允許變量為空,這時你就可以把變量聲明為引用。
? ? “但是,請等一下”,你懷疑地問,“這樣的代碼會產生什么樣的后果?”
?
? ? char *pc = 0; ?// 設置指針為空值
? ? char& rc = *pc;// 讓引用指向空值
?
? ? 這是非常有害的,毫無疑問。結果將是不確定的(編譯器能產生一些輸出,導致任何事情都有可能發生),應該躲開寫出這樣代碼的人除非他們同意改正錯誤。如果你擔心這樣的代碼會出現在你的軟件里,那么你最好完全避免使用引用,要不然就去讓更優秀的程序員去做。我們以后將忽略一個引用指向空值的可能性。
?
? ? 因為引用肯定會指向一個對象,在C++里,引用應被初始化。
??? string& rs; // 錯誤,引用必須被初始化

??? string s("xyzzy");

??? string& rs = s; // 正確,rs指向s

??? 指針沒有這樣的限制。

??? string *ps; // 未初始化的指針

??? // 合法但危險

?
? ? 不存在指向空值的引用這個事實意味著使用引用的代碼效率比使用指針的要高。因為在使用引用之前不需要測試它的合法性。
void printDouble(const double& rd)
{
???? cout << rd; // 不需要測試rd,它
} // 肯定指向一個double值
相反,指針則應該總是被測試,防止其為空:
void printDouble(const double *pd)
{
???? if (pd)

???? { // 檢查是否為NULL
?????????? cout << *pd;
???? }
}

?
?
? ? 指針與引用的另一個重要的不同是指針可以被重新賦值以指向另一個不同的對象。但是引用則總是指向在初始化時被指定的對象,以后不能改變。
??string s1("Nancy");
string s2("Clancy");
string& rs = s1; // rs 引用 s1
string *ps = &s1; // ps 指向 s1
rs = s2; // rs 仍舊引用s1,
// 但是 s1的值現在是
// "Clancy"
ps = &s2; // ps 現在指向 s2;
// s1 沒有改變
?
? ? 總的來說,在以下情況下你應該使用指針,
? ? 一是你考慮到存在不指向任何對象的可能(在這種情況下,你能夠設置指針為空),
? ? 二是你需要能夠在不同的時刻指向不同的對象(在這種情況下,你能改變指針的指向)。如果總是指向一個對象并且一旦指向一個對象后就不會改變指向,那么你應該使用引用。
? ??還有一種情況,就是當你重載某個操作符時,你應該使用引用。
? ? 最普通的例子是操作符[].這個操作符典型的用法是返回一個目標對象,其能被賦值。
??vector<int> v(10); // 建立整形向量(vector),大小為10;
// 向量是一個在標準C庫中的一個模板(見條款35)
v[5] = 10; // 這個被賦值的目標對象就是操作符[]返回的值
如果操作符[]返回一個指針,那么后一個語句就得這樣寫:
*v[5] = 10;
?
? ? 但是這樣會使得v看上去象是一個向量指針。因此你會選擇讓操作符返回一個引用。(這有一個有趣的例外,參見條款30)
? ? 當你知道你必須指向一個對象并且不想改變其指向時,或者在重載操作符并為防止不必要的語義誤解時,你不應該使用指針。而在除此之外的其他情況下,則應使用指針假設你有
?
?void func(int* p, int&r);
int a = 1;
int b = 1;
func(&a,b);
? ?
? ?指針本身的值(地址值)是以pass by value進行的,你能改變地址值,但這并不會改變指針所指向的變量的值,
? ? p = someotherpointer; //a is still 1
?
? ? 但能用指針來改變指針所指向的變量的值,
? ? *p = 123131; // a now is 123131
?
? ? 但引用本身是以pass by reference進行的,改變其值即改變引用所對應的變量的值
? ? r = 1231; // b now is 1231
?
? ??盡可能使用引用,不得已時使用指針。
?
? ??當你不需要“重新指向”時,引用一般優先于指針被選用。這通常意味著引用用于類的公有接口時更有用。引用出現的典型場合是對象的表面,而指針用于對象內部。
?
? ? 上述的例外情況是函數的參數或返回值需要一個“臨界”的引用時。這時通常最好返回/獲取一個指針,并使用 NULL 指針來完成這個特殊的使命。(引用應該總是對象的別名,而不是被解除引用的 NULL 指針)。
?
? ? 注意:由于在調用者的代碼處,無法提供清晰的的引用語義,所以傳統的 C 程序員有時并不喜歡引用。然而,當有了一些 C++ 經驗后,你會很快認識到這是信息隱藏的一種形式,它是有益的而不是有害的。就如同,程序員應該針對要解決的問題寫代碼,而不是機器本身。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384361.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384361.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384361.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql遠程連接權限grant all privileges on *.* to ‘root‘@‘%‘ identified by ‘123456‘ with grant option語句報錯

mysql遠程連接權限grant all privileges on *.* to ‘root‘‘%‘ identified by ‘123456‘ with grant option語句報錯記錄一下自己安裝mysql遇到的小坑grant all privileges on *.* to ‘root‘‘%‘ identified by ‘123456‘ with grant option只適用于mysql8.0之前的版本…

C++虛繼承的概念

轉載&#xff1a;http://blog.csdn.net/crystal_avast/article/details/7678704 C中虛擬繼承的概念 為了解決從不同途徑繼承來的同名的數據成員在內存中有不同的拷貝造成數據不一致問題&#xff0c;將共同基類設置為虛基類。這時從不同的路徑繼承過來的同名數據成員在內存中就只…

數組名和取數組名的區別

先來個簡單的小案例 #include <stdio.h> #include <iostream>using namespace std;int main() {int a[10] { 0 };printf("%d\n", a);printf("%d\n", &a);printf("%d\n", a1);printf("%d\n", &a1);printf("…

C++繼承詳解三 ----菱形繼承、虛繼承

轉載&#xff1a;http://blog.csdn.net/pg_dog/article/details/70175488 今天呢&#xff0c;我們來講講菱形繼承與虛繼承。這兩者的講解是分不開的&#xff0c;要想深入了解菱形繼承&#xff0c;你是繞不開虛繼承這一點的。它倆有著什么關系呢&#xff1f;值得我們來剖析。 菱…

Linux :IO多路復用模型

轉載&#xff1a;http://blog.csdn.net/mr253727942/article/details/50827127 一、IO多路復用定義 IO多路復用允許應用在多個文件描述符上阻塞&#xff0c;并在某一個可以讀寫時通知&#xff0c; 一般遵循下面的設計原則&#xff1a;、 IO多路復用&#xff1a;任何文件描述符…

leetcode(一)刷題兩數之和

給定一個整數數組 nums 和一個整數目標值 target&#xff0c;請你在該數組中找出 和為目標值 target 的那 兩個 整數&#xff0c;并返回它們的數組下標。 示例 1&#xff1a; 輸入&#xff1a;nums [2,7,11,15], target 9 輸出&#xff1a;[0,1] 解釋&#xff1a;因為 nums[…

Linux并發服務器編程之多線程并發服務器

轉載&#xff1a;http://blog.csdn.net/qq_29227939/article/details/53782198 上一篇文章使用fork函數實現了多進程并發服務器&#xff0c;但是也提到了一些問題&#xff1a; fork是昂貴的。fork時需要復制父進程的所有資源&#xff0c;包括內存映象、描述字等&#xff1b;目…

leetcode(二)二分法查找算法

給定一個 n 個元素有序的&#xff08;升序&#xff09;整型數組 nums 和一個目標值 target &#xff0c;寫一個函數搜索 nums 中的 target&#xff0c;如果目標值存在返回下標&#xff0c;否則返回 -1。 示例 1: 輸入: nums [-1,0,3,5,9,12], target 9 輸出: 4 解釋: 9 出現在…

leetcode(977)有序數組的平方

給你一個按 非遞減順序 排序的整數數組 nums&#xff0c;返回 每個數字的平方 組成的新數組&#xff0c;要求也按 非遞減順序 排序。 示例 1&#xff1a; 輸入&#xff1a;nums [-4,-1,0,3,10] 輸出&#xff1a;[0,1,9,16,100] 解釋&#xff1a;平方后&#xff0c;數組變為 […

IO多路復用之select全面總結(必看篇)

轉載&#xff1a;http://www.jb51.net/article/101057.htm 1、基本概念 IO多路復用是指內核一旦發現進程指定的一個或者多個IO條件準備讀取&#xff0c;它就通知該進程。IO多路復用適用如下場合&#xff1a; &#xff08;1&#xff09;當客戶處理多個描述字時&#xff08;一般…

leetcode(189) 旋轉數組

**給定一個數組&#xff0c;將數組中的元素向右移動 k 個位置&#xff0c;其中 k 是非負數。 進階&#xff1a; 盡可能想出更多的解決方案&#xff0c;至少有三種不同的方法可以解決這個問題。 你可以使用空間復雜度為 O(1) 的 原地 算法解決這個問題嗎&#xff1f; 示例 1: …

I/O 多路復用之select

轉載&#xff1a;http://blog.csdn.net/u012432778/article/details/47347133 概述 Linux提供了三種 I/O 多路復用方案&#xff1a;select&#xff0c;poll和epoll。在這一篇博客里先討論select, poll 在將下一篇中介紹&#xff0c;epoll是Linux特有的高級解決方案&#xff0c;…

leetcode(283)移動零

283. 移動零 給定一個數組 nums&#xff0c;編寫一個函數將所有 0 移動到數組的末尾&#xff0c;同時保持非零元素的相對順序。 示例: 輸入: [0,1,0,3,12] 輸出: [1,3,12,0,0] 說明: 必須在原數組上操作&#xff0c;不能拷貝額外的數組。 盡量減少操作次數。 方法一&#xff1…

exec函數族實例解析

轉載&#xff1a;http://www.cnblogs.com/blankqdb/archive/2012/08/23/2652386.html fork()函數通過系統調用創建一個與原來進程(父進程)幾乎完全相同的進程(子進程是父進程的副本&#xff0c;它將獲得父進程數據空間、堆、棧等資源的副本。注意&#xff0c;子進程持有的是上述…

leetcode(167)兩數之和 II - 輸入有序數組

兩數之和 II - 輸入有序數組 給定一個已按照 升序排列 的整數數組 numbers &#xff0c;請你從數組中找出兩個數滿足相加之和等于目標數 target 。 函數應該以長度為 2 的整數數組的形式返回這兩個數的下標值。numbers 的下標 從 1 開始計數 &#xff0c;所以答案數組應當滿足 …

常量指針與指針常量的區別(轉帖)

轉載&#xff1a;http://www.cnblogs.com/witty/archive/2012/04/06/2435311.html 三個名詞雖然非常繞嘴&#xff0c;不過說的非常準確。用中國話的語義分析就可以很方便地把三個概念區分開。 一) 常量指針。 常量是形容詞&#xff0c;指針是名詞&#xff0c;以指針為中心的一個…

c/c++錯題總結

1.類名 對象名 默認調用“對象名()”這個構造函數&#xff0c;在棧內存中存在對象名&#xff0c;在堆內存中存在實際對象&#xff1b; 2.類名 對象名(一個或以上個參數) 默認調用相應的構造函數&#xff0c;在棧內存中存在對象名&#xff0c;在堆內存中也是存在實際對象的&a…

智能指針學習筆記

轉載&#xff1a;http://www.cnblogs.com/wuchanming/p/4411878.html 1. 介紹 本文介紹智能指針的使用。智能指針是c 中管理資源的一種方式&#xff0c;用智能指針管理資源&#xff0c;不必擔心資源泄露&#xff0c;將c 程序員 從指針和內存管理中解脫出來&#xff0c;再者&…

c++程序編譯過程

c程序編譯分成四個過程&#xff1a;編譯預處理&#xff0c;編譯&#xff0c;匯編&#xff0c;鏈接 編譯預處理&#xff1a;處理以#為開頭 編譯&#xff1a;將.cpp文件翻譯成.s匯編文件 匯編&#xff1a;將.s匯編文件翻譯成機器指令.o文件 鏈接&#xff1a;匯編生產的目標文件.o…

仿函數(函數對象)

轉載&#xff1a;http://www.cnblogs.com/wuchanming/p/4411867.html 本文乃作者學習《C標準程序庫》的學習筆記&#xff0c;首先介紹了仿函數&#xff08;函數對象&#xff09;和函數適配器&#xff08;配接器&#xff09;的概念&#xff0c;然后列出STL中所有的仿函數&#x…