靈活而奇特的C++語言特性——const(一)

       學習了博主的《漫談繼承技術》系列博文之後,相信大家都有所收穫吧!這次博主將和大家一起探討 《靈活而奇特的C++語言特性》 ,主要包括引用、常量(const)、常量表達式(constexpr)、靜態(static)、外部(expert)、類型定義(typedef)、類型別名(aliases)、類型轉換、作用域解析、統一初始化、顯示轉換運算符、特性(attribute)、用戶自定義文本、頭文件、可變長度參數列表和預處理器宏。儘管這個知識清單顯得有點凌亂,但是這些話題都是博主經過精心挑選,是容易混淆的語言特性。本篇我們來學習一下const,增進大家對《靈活而奇特的C++語言特性》的理解。

       const是constant的縮寫,指保持不變的量。編譯器會執行這一要求,任何嘗試改變常量的行爲都會當作錯誤處理。此外,當啓用了優化時,編譯器可以利用此信息生成更好的代碼。關鍵字const主要有兩種相關的用法。可以用這個關鍵字標記變量或者參數,也可以用const標記方法。本篇博文主要探討const變量和參數的含義,希望對大家有一點幫助。

const變量和參數

在使用const之前,讓我們先來了解一下const的特性:

①const常量,在定義時必須初始化。

②const常量,在編譯的過程中將該常量替換爲初始化時的值。

③可以通過強制類型轉換將常量的地址賦給指針變量,通過指針變量來修改所指向的空間裏的值。

 

咱們舉個栗子吧:

#include <iostream>

using namespacestd;

 

int main(intargc,char**argv)

{

    //定義const常量

    constintnCValue = 10;

    constdoublePI = 3.141592653;

    //constint size;

 

    //通過強制類型轉換,使指針指向const常量

    int*nPtr = (int*)&nCValue;

    double*dPtr = (double*)&PI;

 

    //通過指針修改const修飾的常量值

    *nPtr =20;

    *dPtr =4.5;

 

    cout<< "*nPtr: "<< *nPtr << endl;

    cout<< "nCValue: "<< nCValue << endl;

 

    cout<< "*dPtr: "<< *dPtr << endl;

    cout<< "PI: " << PI << endl;

 

    return0;

}

 

程序運行結果:


         注意,上面的特性要視具體的編譯器而定,以上是我在VS 2013上的測試結果。我在圖釋中所說的整型包括bool、char、short、int和long型等數據類型。

         如果將上面代碼中的“constint size;”解註釋,編譯器將會報以下錯誤:

 

       可能有的小夥伴會問:“C語言中的const和C++中的const有什麼不同,爲什麼有的時候我將C++中編譯通過的代碼放到C源文件中就會出現編譯錯誤?”。善於發現問題,說明你已經比別人強很多。其實,C語言中const定義的是隻讀變量,不是真正意義上的常量,C++中const定義的纔是真正意義上的常量。那什麼是真正意義上的常量呢?下面我們一起來揭祕一下吧。

#define _CRT_SECURE_NO_WARNINGS//關閉安全性檢測

#include <iostream>

using namespacestd;

 

enum COLOR{RED = 20, BLUE,GREEN };

 

int main(intargc,char**argv)

{

    constintsize = 20;

    intnArray[size] = { 0 };//C源文件中次行語句報錯

    inti = 0;

 

    //初始化數組

    for(auto&var : nArray)

    {

        var =++i;

    }

 

    //輸出數組所有元素

    cout<< "nArray = {";

    foreach(autovar in nArray)

    {

        cout<< var << ", ";

    }

    cout<< "}" << endl;

 

    //switch的參數必須要是整型常量

    switch(size)//C中次行語句報錯

    {

    caseCOLOR::RED:

        printf("size is equal COLOR::RED\n");

        break;

    caseCOLOR::BLUE:

        printf("size is equal COLOR::RED\n");

        break;

    default:

        printf("size is not in COLOR\n");

        break;

    }

 

    return0;

}

 

程序運行結果:


       在C語言中,const修飾的是隻讀變量,其實它本質還是變量,在真正需要使用常量的地方都會報語法錯誤。而C++中對const進行了擴充,使其修飾的是真正意義上的常量。

 

       可以使用const來“保護”變量不被修改。這個關鍵字的一個重要用法是替換define來定義常量,這是const最直接的應用。上面程序中已經舉過栗子啦,這裏就不在贅述。可能有的小夥伴會問:“那const和define到底有什麼區別呢?還是隻是提供了一種新的定義常量的方式而已?”。當然不是啦,const比define更實用更安全,接下來就讓我們一起來探討const和define之間的區別吧。

const和define之間的主要區別:

         ①define定義的常量在預處理時進行替換,const定義的常量在編譯的過程中進行替換

         ②define只是進行簡單的字符替換,不進行類型檢查,const則進行類型檢查

         ③define定義的常量不會分配空間,而const則會分配空間

         ④define定義的常量不支持調試(不能查看它在內存空間裏的值),而const定義的常量則可以。

         ⑤define不能定義形參,const則可以定義形參

         關於這些區別的測試就留給大家啦,博主就不再編寫相關代碼了。

 

       const修飾變量,這個變量包括指針變量。可能有的小夥伴聽說過指針常量和常量指針的概念,並對此十分困惑,總是搞混。沒關係,初學指針碰點壁也是很正常的。接下來我們就一起來聊聊它們之間的差異吧。

#include <iostream>

using namespacestd;

 

int main(intargc,char**argv)

{

    intnValue1 = 10;

    intnValue2 = 20;

 

    //nPtr是常量指針

    constint*nPtr = &nValue1;

    //nCPtr是指針常量

    int* const nCPtr = &nValue2;

 

    //常量指針:不能通過指針修改所指向對象的值,但可以更改其指向,指向其他對象

    //*nPtr= 30;

    nPtr =&nValue2;

 

    //指針常量:不能更改其指向,指向其他對象,但可以通過指針修改所指向對象的值

    //nCPtr= &nValue1;

    *nCPtr =50;

 

    cout<< "nValue1: "<< nValue1 << endl;

    cout<< "nValue2: "<< nValue2 << endl;

 

    return0;

}

 

程序運行結果:


       上述代碼中“constint*nPtr = &nValue1;”也可以寫成“intconst *nPtr = &nValue1;”,其效果是一樣的。然而,這一規則卻不適應與“int* const nCPtr = &nValue2;”,將該語句寫爲“int* nCPtr const = &nValue2;”或“intconst* nCPtr = &nValue2;”則不行,直接改變了語句,甚至無法通過編譯。

       可以嘗試着從右向左讀,“int* const nCPtr = &nValue2;”,const與nCPtr現結合,就知道nCPtr是一個指向int的const指針。另一方面,“int const*nPtr = &nValue1;”,“*”先和nPtr結合,就知道nPtr是一個指向const int的指針。

       const可以應用於引用,它通過比應用於指針更簡單。一是,引用默認爲const,無法改變引用所指的對象。因此,無法顯式地將引用標記爲const。二是,無法創建一個引用的引用,所以引用通過只有一層間接取值。獲取多層間接取值的唯一方法是創建指針的引用。舉個栗子:

constint* const * const* const * constPtr = nullptr;

constint* const * const* const * const&ref = Ptr;

       將對象作爲參數傳遞時,默認選擇是const引用。只有在明確需要修改對象時,才能忽略const。const修飾函數參數的的場景我們已經見過,例如拷貝構造函數,構造函數參數等。這裏就不舉栗子了,如果你確實想看栗子的話,就去《靈活而奇特的C++語言特性——引用(下)》,那裏有一個封裝MyString類的栗子。

       關於const變量和參數的含義和使用我們就探討到這裏了,如果你還覺得意猶未盡,就請關注博主的《靈活而奇特的C++語言特性——const(二)》這篇博文,博主在那裏講述了const方法的含義和使用方法。

       如果想了解更多關於C++語言特性相關的知識,請關注博主《靈活而奇特的C++語言特性》系列博文,相信你能夠在那裏尋找到更多有助你快速成長和加深你對C++語言特性相關的知識和一些特性的理解和掌握。當然,如果你想了解關於繼承方面的技術,請關注博主《漫談繼承技術》系列博文。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章