const T、const T*、T *const、const T&、const T*& 的區別


原文地址: http://blog.csdn.net/luoweifu/article/details/45600415

這里的T指的是一種數據類型,可以是int、long、doule等基本數據類型,也可以是自己類型的類型class。單獨的一個const你肯定知道指的是一個常量,但const與其他類型聯合起來的眾多變化,你是不是就糊塗了?下面我們一一來解析。

const T

定義一個常量,聲明的同時必須進行初始化。一旦聲明,這個值將不能被改變。

  1. int i = 5;
  2. const int constInt = 10; //正確
  3. const int constInt2 = i; //正確
  4. constInt = 20; //錯誤,常量值不可被改變
  5. const int constInt3; //錯誤,未被初

const T*

指向常量的指針,不能用於改變其所指向的對象的值。

  1. const int i = 5;
  2. const int i2 = 10;
  3. const int* pInt = &i; //正確,指向一個const int對象,即i的地址
  4. //*pInt = 10; //錯誤,不能改變其所指缶的對象
  5. pInt = &i2; //正確,可以改變pInt指針本身的值,此時pInt指向的是i2的地址
  6. const int* p2 = new int(8); //正確,指向一個new出來的對象的地址
  7. delete p2; //正確
  8. //int* pInt = &i; //錯誤,i是const int類型,類型不匹配,不能將const int * 初始化為int *
  9. int nValue = 15;
  10. const int * pConstInt = &nValue; //正確,可以把int *賦給const int *,但是pConstInt不能改變其所指向對象的值,即nValue
  11. *pConstInt = 40; //錯誤,不能改變其所指向對象的值

const int* 與int* const的區別

指針本身就是一種對象,把指針定義為常量就是常量指針,也就是int* const的類型,也可以寫成int *const,聲明時必須初始化。

  1. int nValue = 10;
  2. int* const p = &nValue;
  3. int *const p2 = &nValue;
  4. const int* 指針指向的對象不可以改變,但指針本身的值可以改變;int* const 指針本身的值不可改變,但其指向的對象可以改變。
  5. int nValue1 = 10;
  6. int nValue2 = 20;
  7. int* const constPoint = &nValue1;
  8. //constPoint = & nValue2; //錯誤,不能改變constPoint本身的值
  9. *constPoint = 40; //正確,可以改變constPoint所指向的對象,此時nValue1 = 40
  10. const int nConstValue1 = 5;
  11. const int nConstValue2 = 15;
  12. const int* pPoint = &nConstValue1;
  13. //*pPoint = 55; //錯誤,不能改變pPoint所指向對象的值
  14. pPoint = &nConstValue2; //正確,可以改變pPoint指針本身的值,此時pPoint邦定的是nConstValue2對象,即pPoint為nConstValue2的地址

const int* const 是一個指向常量對象的常量指針,即不可以改變指針本身的值,也不可以改變指針指向的對象。

  1. const int nConstValue1 = 5;
  2. const int nConstValue2 = 15;
  3. const int* const pPoint = &nConstValue1;
  4. //*pPoint = 55; //錯誤,不能改變pPoint所指向對象的值
  5. //pPoint = &nConstValue2; //錯誤,不能改變pPoint本身的值

const T&

對常量(const)的引用,又稱為常量引用,常量引用不能修改其邦定的對象。

  1. int i = 5;
  2. const int constInt = 10;
  3. const int& rConstInt = constInt; //正確,引用及邦定的值都是常量
  4. rConstInt = 5; //錯誤,不能改變引用所指向的對象

允許為一個常量引用邦定一個非常量對象、字面值,甚至是表達式;引用的類型與引用所指向的類型必須一致。

  1. int i = 5;
  2. int& rInt = i; //正確,int的引用
  3. const int constInt = 10;
  4. const int& rConstInt = constInt; //正確,引用及邦定的值都是常量
  5. const int& rConstInt2 = rInt; //正確,用rInt邦定的對象進行賦值
  6. rInt = 30; //這時,rConstInt2、rInt、i的值都為30
  7. //rConstInt2 = 30; //錯誤,rConstInt2是常量引用,rConstInt2本身不能改變所指向的對象
  8. int i2 = 15;
  9. const int& rConstInt3 = i2; //正確,用非常量的對象為其賦值
  10. const int& rConstInt4 = i + i2; //正確,用表達式為其賦值,值為45
  11. i = 20; //此時i=20, rInt = 20, rConstInt4 = 45,說明rConstInt4邦定的是i + i2的臨時變量
  12. const int& rConstInt5 = 50; //正解,用一個常量值為其賦值

const T*&與T *const&

指向常量對象的指針的引用,這可以分兩步來理解:1.const T*是指向常量的指針;2.const T*&指向常量的指針的引用。

  1. const int nConstValue = 1; //常量對象
  2. const int nConstValue2 = 2; //常量對象
  3. const int* pConstValue = &nConstValue; //指向常量對象的指針
  4. const int* pConstValue2 = &nConstValue2; //指向常量對象的指針
  5. const int*& rpConstValue = pConstValue; //指向常量對象的指針的引用
  6. //*rpConstValue = 10; //錯誤,rpConstValue指向的是常量對象,常量對象的值不可改變
  7. rpConstValue = pConstValue2; //正確,此時pConstValue的值等於pConstValue2
  8. //指向常量對象的指針本身是對象,引用可以改變邦定對象的值
  9. int nValue = 5;
  10. int nValue2 = 10;
  11. int *const constPoint = &nValue; //常量指針
  12. int *const constPoint2 = &nValue2; //常量指針
  13. int *const &rpConstPoint = constPoint; //對常量指針的引用,邦定constPoint
  14. //rpConstPoint = constPoint2; //錯誤,constPoint是常量指針,指針本身的值不可改變
  15. *rpConstPoint = 20; //正確,指針指向的對象可以改變

在函數中的應用

我們直接從需求出來,假設有這樣一個數據結構:

  1. typedef struct __Data
  2. {
  3. int value;
  4. public:
  5. __Data()
  6. :value(0){}
  7. }Data;

1.希望傳入一個對象,又不想讓函數體修改這個對象。

方式<1>

  1. void Dealwith(const Data& data)
  2. {
  3. cout << data.value << endl;
  4. //data.value = 5; //錯誤,data是常量引用,不能改變其邦定的對象
  5. }

這種方式還有一個好處是只有在調用函數的時候會邦定對象,傳遞的是對象的引用,而不是對象,減少函數調用時對象賦值的花銷。

方式<2>

  1. void Dealwith(const Data* pData)
  2. {
  3. cout << pData->value << endl;
  4. //pData->value = 5; //錯誤,pData是指向常量對象的指針,不能改變其指向的對象
  5. }

這種方式與void Dealwith(const Data& data)的功能相同

方式<3>

  1. Data g_data(20);
  2. void Dealwith(const Data*& pData)
  3. {
  4. cout << pData->value << endl;
  5. //pData->value = 5; //錯誤,pData邦定的是指向常量對象的指針,常量對象的指針不能改變其指向的對象
  6. pData = &g_data; //正確,pData是[指向常量對象的指針]的引用,引用可改變其邦定的對象
  7. }

調用如下:

  1. Data d(10);
  2. const Data* pData = &d;
  3. Dealwith(pData);
  4. cout << pData->value << endl; //此時pData->value為20,d.value還是10

這種方式函數未改變傳入的對象的值,但可以返回另外一個對象的指針。注意返回的指針必須指向全局的對象,如果返回函數內定義的對象,退出函數作用域后,其指針將無效,這是非常危險的;如果Dealwith是成員函數,也可以返回指向成員的指針。

2.在類中的使用,返回一個類的成員,但不希望調用方修改這個成員。

方式<1>

  1. class MyData
  2. {
  3. public :
  4. MyData(std::string name, Data data)
  5. {
  6. m_name = name;
  7. m_data = data;
  8. }
  9. const Data* GetData()
  10. {
  11. return &m_data;
  12. }
  13. private:
  14. std::string m_name;
  15. Data m_data;
  16. };

調用如下:

  1. MyData mydata("", Data(100));
  2. const Data* pData = mydata.GetData();
  3. cout << pData->value << endl; //pData->value = 100
  4. //pData->value = 50; //錯誤,pData是指向常量對象的指向,不能改變其指向對象的值

方式<2>

有人可能會問GetData也可以寫成這樣:

  1. const Data& GetData()
  2. {
  3. return m_data;
  4. }

這樣的話,調用方常常容易寫成這樣:

  1. MyData mydata("", Data(100));
  2. Data data = mydata.GetData(); //這會有個賦值的過程,會把mydata.m_data賦給data
  3. cout << data.value << endl; //data.value = 100
  4. data.value = 50; //正確,data.value=50,但mydata.m_data.value還是100

這樣調用時會有一個結果賦值的過程,如果Data是一個復雜的類,會有較大的開銷,其效果與下面這種方式是一樣的:

  1. Data GetData()
  2. {
  3. return m_data;
  4. }

當然,如果調用方這樣使用是正確的:

  1. const Data& GetData()
  2. {
  3. return m_data;
  4. }
  1. MyData mydata("", Data(100));
  2. const Data& data = mydata.GetData(); //這會有個賦值的過程,會把mydata.m_data賦給data
  3. cout << data.value << endl; //data.value = 100
  4. //data.value = 50; //錯誤,data是一個對常量的引用,不能改變其邦定的對象

這對調用方的技術能力要求比較高,如果你是設計方,一定要盡量使接口簡單易用。

方式<3>

如果你要傳入一個Data進行一些處理,處理完后返回類的成員m_data,可如下實現:

  1. void DoSomething(const Data*& pData)
  2. {
  3. if (pData != NULL)
  4. {
  5. // doto: 這里實現你要處理的功能
  6. }
  7. pData = &m_data;
  8. }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM