<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        C++中const與指針、引用的分析

        作者:龔平   來源:本站原創   點擊數:  更新時間:2014年03月13日   【字體:

            C++中函數的參數相比C語言中的函數參數要復雜的多,其中主要的原因是C++中引入了引用以及const限定符。這兩個對象的引入,使得C++中的函數參數變得異常的復雜多變,每一種類型都具有比較適合的使用范圍。
        本文詳細的分析const與指針、引用在一起存在情況下的情況分析。
         
        首先介紹引用
            引用是對象的別名,必須在初始化的過程中與一個具體的對象綁定起來,綁定完成以后就再也不能夠修改了,引用貌似和指針有很大的相似性,但是引用是引用,是一個別名,而指針是一個變量,只是變量中保存的是對象的地址,引用并不分配新的內存空間。因此一個引用與一塊內存區域綁定,是這塊內存區域的別名,就如同數組名一樣,數組是內存中的一塊區域,數組名是這塊區域的名字,但是在內存中并不存在額外的區域保存數組名。引用就是一塊內存區域的別名。C++中變量實質上就是一塊內存區域,我們在用&i就可以得到變量i的地址,也就是說變量是這塊區域的名字。對變量的操作實質上就是對這塊內存中內容的操作。別名是這塊區域的另一個名字。采用任何一個名字對這塊區域修改都會影響區域的內容。

         

            int vari = 10;
            int &refr = vari;
            vari = 20;
            cout << refr << " " << vari << endl;
            refr = 30;
            cout << refr << " " << vari << endl;

        上面的int &refr = vari實質上就是變量vari的別名,也就是保存vari變量地址的別名,這個地址中保存的是一個int類型的數據,數據可以通過vari來操作,可以修改。因為refr是一個別名,也可以通過該別名對這塊內存區域進行操作。也就是說別名的操作就是針對一塊特定的內存區域,這個通過變量操作的效果是一致的。
        其次說說const限定符
            const的引入使得在函數操作中的一些問題復雜了,但是更加的合理了,const限定符是指上是指一個常量。這個常量在一般的情況下就是限定變量不能修改,但是當這個限定符與引用、指針結合在一起時,使得很多的問題不在明朗。
         
            1、const與指針

         

            int *ptr;
            const int *ciptr;
            int const *icptr;
            int * const cptr;
            const int * const cicptr;

        上面是關于const與指針結合時的各種情況,這并不只是C++中經常遇到的問題,在C語言中也會有類似的討論,雖然const并不是C語言中的關鍵字。
        int * ptr         是指定義一個指向int 類型的指針ptr。
        const int *ciptr 是指定義一個指向const int 類型的指針ciptr,這是const 限定的是(* ciptr),也就是對指針解引用,即const限定的就是數據本身,而非指針。所以ciptr是一個指向常int型數據的指針。
        int const * icptr其實和上面的const int *ciptr是一致的因為const只是一個限定符,在int前還是后都 沒有影響,他限定的仍然是(*icptr),并不是icptr,也就是icptr也是指向常int型數據的指針,也就是說在icptr這個指針看來,它指向的數據是常數,是不能改變的,但是是否真的不能改變,需要依據實際的類型的分析,只是不能通過這個指針來改變。也就是說該指針是一個自以為自己指向常量的指針。
        int * const cptr 這時候我們還是結合const的位置分析,const限定的是cptr,cptr我們可以知道是一個指針,也就是說const限定的是一個指針,而不是指針指向的數據,也就是說這種定義實質上是定義一個常指針,也就是指針指向的地址是不變的,也就是cptr是不能被賦值的,不能采用這個指針指向其他的對象或者地址。但是這個地址中的數據并不是常數,是可以改變的,可以通過對*cptr進行修改。這種指針實質上也就使得指針的效果大大減小,并不常用。
        const int * const cicptr 這種定義結合上面的分析我們知道是一個指向常量的常指針,也就說這個指針指向的地址是一個常地址,指針不能指向其他的對象或者地址。同時對指針cicptr來說,我指向的這個地址中的內容也是不能修改的,是一個常量,是不能修改的,但是該地址的數據能否修改還需要進行實際的分析。
         
            2、關于指針的初始化、賦值的問題
            對于const類型的數據,如果需要定義指針,這時候只能定義const類型的數據,這是為什么呢?因為對于const對象來說,數據是肯定不能修改的,如果定義指向非const的指針,程序員可能就會通過指針來修改對象的值,但是const對象是不能被修改的,肯定會出現錯誤。因此const的變量只能采用指向常量的指針來指向。一般來說如果將一個非const指針指向了一個const對象,編譯的過程中就會拋出如下的錯誤:

            invalid conversion from ‘const int*’ to ‘int*’

            但是對于指向常量的指針并不一定指向的數據就是常量,這是一個非常重要的技術點,指向常量的指針指向的數據只是針對這個指針而言,他認為自己指向的數據是常量,休想通過他來修改指向的對象。也就是說指向常量的指針在初始化、賦值的時可以初始化或者賦值為非const變量的地址,即可以指向非const的對象,只是不能通過該指針來修改對象罷了。
            同時需要注意:對于指向const的指針,初始化過程比較方便,不要求是const對象的地址,可以采用非const對象的地址初始化,甚至還可以采用指向非const的指針直接賦值初始化,這時指針自己認為自己指向的對象是常量。但是不能將指向const的指針直接賦值給指向非const的指針,如果不小心賦值也會出現上面出現的問題。下面參看一段小的代碼,說明其中的一些問題。

         

            #include <iostream>
            #include <string>
            #include <vector>

            using namespace std;

            int main()
            {
                    int num = 20;
                    const int array_size = 10;

               
                    int *pnum = &num;
                    const int * cpnum = &num;
                    /*const int *指針可以采用int *指針直接初始化*/
                    const int *csize1 = pnum;


                    /*但是int * 指針不能采用const int *制作初始化*/
                    //int *psize = &array_size;
                    /*const類型數據只能采用指向const的指針來指向*/
                    const int *csize = &array_size;

                    cout << "Before change..." << endl;
                    cout << "The num of num = " << num << endl;
                    cout << "*pnum = " << *pnum << " "
                            << "*cpnum = " << *cpnum << " "
                            << "csize1 = " << *csize1 << endl;

                    num = 30;
               
                    cout << "After changed..." << endl;
                    cout << "The num of num = " << num << endl;
                    cout << "*pnum = " << *pnum << " "
                            << "*cpnum = " << *cpnum << " "
                            << "csize1 = " << *csize1 << endl;

                    return 0;
            }

         
            從上面的結果我們可以知道指向const的指針可以采用非const變量的地址進行初始化或者賦值操作,同時也可以采用指向非const指針直接初始化指向const的指針。同時指向const的指針不能賦值給指向非const的指針,會出現const int *不能轉換到int *的問題。

            3、const與引用
            關于const和引用在一起情況下也存在一些類似于指針的情況,但是畢竟引用相比指針要簡單,這時候情況也比較簡單.但是我認為分析引用應該與分析指針是一樣也存在類似的問題。但是引用就只有兩種,非const的引用和const的引用。

         

            int num = 10;

            int &newname = num;
            const int &othername = num;

           引用主要是上面的兩種,這兩種的區別相對來說比較大,而且加入了const限定符以后,引用的能力往往變的更加的強大。
           一般來說對于const對象而言,一般只能采用const引用,這與前面的const對象只能采用指向const對象的原因是一樣的,如果對引用沒有進行限定,可能會通過引用修改數據,這是不允許的。也就是說const引用與指向const對象的指針有一定的相似性,即不能通過這個引用或者指針來修改原來的數據。保證數據的const特性。也就是說非const引用不能引用const對象,如果不小心引用編譯器會出現下面的錯誤:

            invalid initialization of reference of type ‘int&’ from expression of type ‘const int’

        因此非const引用只能針對非const的同類型數據。這是需要注意的。比如string,和字符串字面值都不能直接引用。因為類型不相同,這是在C++函數定義中經常出現的問題,在后期的博文中再分析。在引用中加入const的就是對于這個引用而言,不能通過自己來修改原始的數據,這與指向const的指針有很大的相似性,
         
            但是往往const引用的初始化并不一定要去對象是const的,甚至可以是不同類型的對象,這種優越性是連指針(指針只能指向同一類型的數據,如果一定要指向需要強制類型轉換)都沒有的,也就是可以將不同類型的非const或者const對象來初始化一個const引用。但是這個const限定符就限定了該引用指向的對象是不能通過該引用來修改的。如果嘗試采用const的引用進行修改,編譯器會出現如下的錯誤:

            error: assignment of read-only reference...

            綜合上面的描述可知:非const引用只能綁定到該引用同類型(string和字符串字面值(const char *)之間都不可以)的非const對象,而const引用則可以綁定到任意的一種對象上(非const、const、甚至不同類型),這種差別在函數的參數中有較大的體現。
            通過下面的例子來說明一下上面的分析:

         

            #include <iostream>
            #include <string>
            #include <vector>

            using namespace std;

            int main()
            {
                    int num = 20;
                    const int array_size = 10;

                    int &pnum = num;
                    const int &cpnum = num;
                    /*采用引用直接初始化const類型的引用*/
                    const int &csize1 = pnum;

                    /*const的變量不能采用非const的引用*/
                    //int &psize = array_size;
                    /*const類型數據只能采用指向const的指針來指向*/
                    const int &csize = array_size;

                    cout << "Before change..." << endl;
                    cout << "The num of num = " << num << endl;
                    cout << "pnum = " << pnum << " "
                            << "cpnum = " << cpnum << " "
                            << "csize1 = " << csize1 << endl;

                    num = 30;
                    cout << "After the first changed..." << endl;
                    cout << "The num of num = " << num << endl;
                    cout << "pnum = " << pnum << " "
                            << "cpnum = " << cpnum << " "
                            << "csize1 = " << csize1 << endl;
              
                    /*通過引用修改變量的值*/
                    pnum = 40;
                    cout << "After the second changed..." << endl;
                    cout << "The num of num = " << num << endl;
                    cout << "pnum = " << pnum << " "
                            << "cpnum = " << cpnum << " "
                            << "csize1 = " << csize1 << endl;

                    /*不能采用const的引用修改對象,
                    *這與指向const的指針特性的相似處*/
                    /*
                    csize1 = 50;
                    cout << "After the second changed..." << endl;
                    cout << "The num of num = " << num << endl;
                    cout << "pnum = " << pnum << " "
                            << "cpnum = " << cpnum << " "
                            << "csize1 = " << csize1 << endl;
                    */

                    double dnum = 10.1;
                    /*非const的引用只能綁定相同類型的對象*/
                    //int &dname = dnum;

                    /******************************************
                    *const引用可以綁定不同類型的對象,
                    *因此const引用就能更加方便的作為函數的形參
                    *******************************************/
                    const int &dothername = dnum;

                    return 0;
            }


        上面的實驗結果基本上符合分析的結論。
         
        總結
            const的使得引用與指針的變化更加復雜,總體而言,const主要是保證了通過指針或者引用不修改原始的數據,但是至于原始的數據是否可以修改,這就需要參看數據的類型。
            在存在const的對象中,只能采用包含限定符const的引用或者指向const的指針來操作。
            const的引用比較強大,初始化的過程中可以采用任意的對象,const對象,非const對象,甚至其他類型的數據。const引用支持隱式類型轉換。而指向const的指針則不能,只能指向同一類型的數據,但是可以采用強制類型轉換,初始化或者賦值過程中對數據類型沒有要求,可以是const對象的地址,也可以是非const對象的地址。
            const引用和指向const對象的指針都是自己以為自己指向的對象是不能修改的,采用const的指針或者引用就能避免原始數據修改。

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮