青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

寶杉的博客

UNIX/LINUX;ACE;SNMP;C++
posts - 33, comments - 23, trackbacks - 0, articles - 0
 

1、什么是const?
   常類型是指使用類型修飾符const說明的類型,常類型的變量或對象的值是不能被更新的。(當然,我們可以偷梁換柱進行更新:)

2、為什么引入const?
  const 推出的初始目的,正是為了取代預編譯指令,消除它的缺點,同時繼承它的優點。

3、cons有什么主要的作用?
   (1)可以定義const常量,具有不可變性。
        例如:
             const int Max=100;
             int Array[Max];       
   (2)便于進行類型檢查,使編譯器對處理內容有更多了解,消除了一些隱患。
 例如:
             void f(const int i) { .........}
        編譯器就會知道i是一個常量,不允許修改;
   (3)可以避免意義模糊的數字出現,同樣可以很方便地進行參數的調整和修改。
        同宏定義一樣,可以做到不變則已,一變都變!如(1)中,如果想修改Max的內容,只需要:const int Max=you want;即可!
   (4)可以保護被修飾的東西,防止意外的修改,增強程序的健壯性。
        還是上面的例子,如果在函數體內修改了i,編譯器就會報錯;
        例如:
             void f(const int i) { i=10;//error! }
    (5) 為函數重載提供了一個參考。
         class A
         {
           ......
           void f(int i)       {......} file://一個函數
           void f(int i) const {......} file://上一個函數的重載
            ......
          };
     (6) 可以節省空間,避免不必要的內存分配。
         例如:
              #define PI 3.14159         file://常量宏
              const doulbe  Pi=3.14159;  file://此時并未將Pi放入ROM中
              ......
              double i=Pi;               file://此時為Pi分配內存,以后不再分配!
              double I=PI;               file://編譯期間進行宏替換,分配內存
              double j=Pi;               file://沒有內存分配
              double J=PI;               file://再進行宏替換,又一次分配內存!
         const定義常量從匯編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程序運行過程中只有一份拷貝,而#define定義的常量在內存中有若干個拷貝。
     (7) 提高了效率。
           編譯器通常不為普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高。

3、如何使用const?
   (1)修飾一般常量
     一般常量是指簡單類型的常量。這種常量在定義時,修飾符const可以用在類型說明符前,也可以用在類型說明符后。
       例如:  
           int const x=2;  或  const int x=2;
   (2)修飾常數組
       定義或說明一個常數組可采用如下格式:
       int const a[5]={1, 2, 3, 4, 5}; 
         const int a[5]={1, 2, 3, 4, 5};
   (3)修飾常對象
      常對象是指對象常量,定義格式如下:
  class A;
       const A a;
         A const a;
      定義常對象時,同樣要進行初始化,并且該對象不能再被更新,修飾符const可以放在類名后面,也可以放在類名前面。 
   (4)修飾常指針
        const int *A;        file://const修飾指向的對象,A可變,A指向的對象不可變
        int const *A;       file://const修飾指向的對象,A可變,A指向的對象不可變
        int *const A;       file://const修飾指針A,     A不可變,A指向的對象可變
        const int *const A;  file://指針A和A指向的對象都不可變
   (5)修飾常引用
        使用const修飾符也可以說明引用,被說明的引用為常引用,該引用所引用的對象不能被更新。其定義格式如下:
       const double & v;
  (6)修飾函數的常參數
        const修飾符也可以修飾函數的傳遞參數,格式如下:
        void Fun(const int Var);
        告訴編譯器Var在函數體中的無法改變,從而防止了使用者的一些無意的或錯誤的修改。    
   (7)修飾函數的返回值:
        const修飾符也可以修飾函數的返回值,是返回值不可被改變,格式如下:
            const int Fun1();
            const MyClass Fun2();
   (8)修飾類的成員函數:
        const修飾符也可以修飾類的成員函數,格式如下:
            class ClassName
     {
             public:
                  int Fun() const;
                    .....
             };
        這樣,在調用函數Fun時就不能修改類里面的數據
    (9)在另一連接文件中引用const常量
         extern const int i;     file://正確的引用
         extern const int j=10;  file://錯誤!常量不可以被再次賦值
    另外,還要注意,常量必須初始化!
         例如:
             const int i=5; 

4、幾點值得討論的地方:
   (1)const究竟意味著什么?
        說了這么多,你認為const意味著什么?一種修飾符?接口抽象?一種新類型?
        也許都是,在Stroustup最初引入這個關鍵字時,只是為對象放入ROM做出了一種可能,對于const對象,C++既允許對其進行靜態初始化,也允許對他進行動態初始化。理想的const對象應該在其構造函數完成之前都是可寫的,在析夠函數執行開始后也都是可寫的,換句話說,const對象具有從構造函數完成到析夠函數執行之前的不變性,如果違反了這條規則,結果都是未定義的!雖然我們把const放入ROM中,但這并不能夠保證const的任何形式的墮落,我們后面會給出具體的辦法。無論const對象被放入ROM中,還是通過存儲保護機制加以保護,都只能保證,對于用戶而言這個對象沒有改變。換句話說,廢料收集器(我們以后會詳細討論,這就一筆帶過)或數據庫系統對一個const的修改怎沒有任何問題。
   (2)位元const V.S. 抽象const?
        對于關鍵字const的解釋有好幾種方式,最常見的就是位元const 和 抽象const。下面我們看一個例子:
        class A
        {
         public:
               ......
               A f(const A& a);
               ......
         };
         如果采用抽象const進行解釋,那就是f函數不會去改變所引用對象的抽象值,如果采用位元const進行解釋,那就成了f函數不會去改變所引用對象的任何位元。
         我們可以看到位元解釋正是c++對const問題的定義,const成員函數不被允許修改它所在對象的任何一個數據成員。
         為什么這樣呢?因為使用位元const有2個好處:
         最大的好處是可以很容易地檢測到違反位元const規定的事件:編譯器只用去尋找有沒有對數據成員的賦值就可以了。另外,如果我們采用了位元const,那么,對于一些比較簡單的const對象,我們就可以把它安全的放入ROM中,對于一些程序而言,這無疑是一個很重要的優化方式。(關于優化處理,我們到時候專門進行討論)
         當然,位元const也有缺點,要不然,抽象const也就沒有產生的必要了。
         首先,位元const的抽象性比抽象const的級別更低!實際上,大家都知道,一個庫接口的抽象性級別越低,使用這個庫就越困難。
         其次,使用位元const的庫接口會暴露庫的一些實現細節,而這往往會帶來一些負面效應。所以,在庫接口和程序實現細節上,我們都應該采用抽象const。
         有時,我們可能希望對const做出一些其它的解釋,那么,就要注意了,目前,大多數對const的解釋都是類型不安全的,這里我們就不舉例子了,你可以自己考慮一下,總之,我們盡量避免對const的重新解釋。
   (3)放在類內部的常量有什么限制?
        看看下面這個例子:
        class A
        {
         private:
           const int c3 = 7;           // ???
       static int c4 = 7;          // ???
       static const float c5 = 7;  // ???
          ......
  };
         你認為上面的3句對嗎?呵呵,都不對!使用這種類內部的初始化語法的時候,常量必須是被一個常量表達式初始化的整型或枚舉類型,而且必須是static和const形式。這顯然是一個很嚴重的限制!
         那么,我們的標準委員會為什么做這樣的規定呢?一般來說,類在一個頭文件中被聲明,而頭文件被包含到許多互相調用的單元去。但是,為了避免復雜的編譯器規則,C++要求每一個對象只有一個單獨的定義。如果C++允許在類內部定義一個和對象一樣占據內存的實體的話,這種規則就被破壞了。
    (4)如何初始化類內部的常量?
         一種方法就是static 和 const 并用,在內部初始化,如上面的例子;
         另一個很常見的方法就是初始化列表:
         class A
         {
          public:
                A(int i=0):test(i) {}
          private:
                const int i;
          };
          還有一種方式就是在外部初始化,例如:
         class A
         {
          public:
                A() {}
          private:
                static const int i;  file://注意必須是靜態的!
          };
          const int A::i=3;
     (5)常量與數組的組合有什么特殊嗎?
          我們給出下面的代碼:
           const int size[3]={10,20,50};
           int array[size[2]];
           有什么問題嗎?對了,編譯通不過!為什么呢?
           const可以用于集合,但編譯器不能把一個集合存放在它的符號表里,所以必須分配內存。在這種情況下,const意味著“不能改變的一塊存儲”。然而,其值在編譯時不能被使用,因為編譯器在編譯時不需要知道存儲的內容。自然,作為數組的大小就不行了:)
         你再看看下面的例子:
          class A
         {
          public:
                A(int i=0):test[2]({1,2}) {} file://你認為行嗎?
          private:
                const int test[2];
          };
         vc6下編譯通不過,為什么呢?
         關于這個問題,前些時間,njboy問我是怎么回事?我反問他:“你認為呢?”他想了想,給出了一下解釋,大家可以看看:我們知道編譯器堆初始化列表的操作是在構造函數之內,顯式調用可用代碼之前,初始化的次序依據數據聲明的次序。初始化時機應該沒有什么問題,那么就只有是編譯器對數組做了什么手腳!其實做什么手腳,我也不知道,我只好對他進行猜測:編譯器搜索到test發現是一個非靜態的數組,于是,為他分配內存空間,這里需要注意了,它應該是一下分配完,并非先分配test[0],然后利用初始化列表初始化,再分配test[1],這就導致數組的初始化實際上是賦值!然而,常量不允許賦值,所以無法通過。
        呵呵,看了這一段冠冕堂皇的話,真讓我笑死了!njboy別怪我揭你短呀:)我對此的解釋是這樣的:C++標準有一個規定,不允許無序對象在類內部初始化,數組顯然是一個無序的,所以這樣的初始化是錯誤的!對于他,只能在類的外部進行初始化,如果想讓它通過,只需要聲明為靜態的,然后初始化。
         這里我們看到,常量與數組的組合沒有什么特殊!一切都是數組惹的禍!
   (6)this指針是不是const類型的?
        this指針是一個很重要的概念,那該如何理解她呢?也許這個話題太大了,那我們縮小一些:this指針是個什么類型的?這要看具體情況:如果在非const成員函數中,this指針只是一個類類型的;如果在const成員函數中,this指針是一個const類類型的;如果在volatile成員函數中,this指針就是一個volatile類類型的。
   (7)const到底是不是一個重載的參考對象?
        先看一下下面的例子:
        class A
         {
           ......
           void f(int i)       {......} file://一個函數
           void f(int i) const {......} file://上一個函數的重載
            ......
          };
        上面是重載是沒有問題的了,那么下面的呢?
         class A
         {
           ......
           void f(int i)       {......} file://一個函數
           void f(const int i) {......} file://?????
            ......
         };
         這個是錯誤的,編譯通不過。那么是不是說明內部參數的const不予重載呢?再看下面的例子:
        class A
         {
           ......
           void f(int& )       {......} file://一個函數
           void f(const int& ) {......} file://?????
            ......
         };
         這個程序是正確的,看來上面的結論是錯誤的。為什么會這樣呢?這要涉及到接口的透明度問題。按值傳遞時,對用戶而言,這是透明的,用戶不知道函數對形參做了什么手腳,在這種情況下進行重載是沒有意義的,所以規定不能重載!當指針或引用被引入時,用戶就會對函數的操作有了一定的了解,不再是透明的了,這時重載是有意義的,所以規定可以重載。
   (8)什么情況下為const分配內存?
        以下是我想到的可能情況,當然,有的編譯器進行了優化,可能不分配內存。
        A、作為非靜態的類成員時;
        B、用于集合時;
        C、被取地址時;
        D、在main函數體內部通過函數來獲得值時;
        E、const的 class或struct有用戶定義的構造函數、析構函數或基類時;。
        F、當const的長度比計算機字長還長時;
        G、參數中的const;
        H、使用了extern時。
        不知道還有沒有其他情況,歡迎高手指點:)       
   (9)臨時變量到底是不是常量?
        很多情況下,編譯器必須建立臨時對象。像其他任何對象一樣,它們需要存儲空間而且必須被構造和刪除。區別是我們從來看不到編譯器負責決定它們的去留以及它們存在的細節。對于C++標準草案而言:臨時對象自動地成為常量。因為我們通常接觸不到臨時對象,不能使用與之相關的信息,所以告訴臨時對象做一些改變有可能會出錯。當然,這與編譯器有關,例如:vc6、vc7都對此作了擴展,所以,用臨時對象做左值,編譯器并沒有報錯。
   (10)與static搭配會不會有問題?
        假設有一個類:
        class A
        {
         public:
             ......
             static void f() const { ......}
             ......
         };
         我們發現編譯器會報錯,因為在這種情況下static不能夠與const共存!
         為什么呢?因為static沒有this指針,但是const修飾this指針,所以...
     (11)如何修改常量?
          有時候我們卻不得不對類內的數據進行修改,但是我們的接口卻被聲明了const,那該怎么處理呢?我對這個問題的看法如下:
           1)標準用法:mutable
              class A
              {
               public:
                      A(int i=0):test(i)        { }
                      void SetValue(int i)const { test=i; }
               private:
                      mutable int test;   file://這里處理!
               };
           2)強制轉換:const_cast
               class A
               {
               public:
                      A(int i=0):test(i)        { }
                      void SetValue(int i)const
                      { const_cast <int>(test)=i; }//這里處理!
               private:
                      int test;  
               };
            3)靈活的指針:int*
               class A
              {
               public:
                      A(int i=0):test(i)        { }
                      void SetValue(int i)const
                      { *test=i; }
               private:
                      int* test;   file://這里處理!
               };
            4)未定義的處理
              class A
              {
               public:
                      A(int i=0):test(i)        { }
                      void SetValue(int i)const
                      { int *p=(int*)&test; *p=i; }//這里處理!
               private:
                      int test;  
               };
                注意,這里雖然說可以這樣修改,但結果是未定義的,避免使用!
             5)內部處理:this指針
              class A
              {
               public:
                      A(int i=0):test(i)        { }
                      void SetValue(int i)const
                      { ((A*)this)->test=i; }//這里處理!
               private:
                      int test;  
               };
             6)最另類的處理:空間布局
               class A
               {
                public:
                      A(int i=0):test(i),c('a') {  }
                private:
                      char c;
                      const int test;
                };
                int main()
                {
                    A a(3);
                    A* pa=&a;
                    char* p=(char*)pa;    
                    int*  pi=(int*)(p+4);//利用邊緣調整
                    *pi=5;                 file://此處改變了test的值!
                    return 0;
                 }
        雖然我給出了6中方法,但是我只是想說明如何更改,但出了第一種用法之外,另外5種用法,我們并不提倡,不要因為我這么寫了,你就這么用,否則,我真是要誤人子弟了:)
     (12)最后我們來討論一下常量對象的動態創建。
           既然編譯器可以動態初始化常量,就自然可以動態創建,例如:
           const int* pi=new const int(10);
           這里要注意2點:
           1)const對象必須被初始化!所以(10)是不能夠少的。
           2)new返回的指針必須是const類型的。
           那么我們可不可以動態創建一個數組呢?
           答案是否定的,因為new內置類型的數組,不能被初始化。
           這里我們忽視了數組是類類型的,同樣對于類內部數組初始化我們也做出了這樣的忽視,因為這涉及到數組的問題,我們以后再討論。

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美日韩成人高清在线一区| 午夜伦理片一区| 欧美freesex交免费视频| 亚洲综合色自拍一区| 9人人澡人人爽人人精品| 亚洲精品永久免费精品| 制服丝袜亚洲播放| 亚洲欧美在线aaa| 久久五月天婷婷| 欧美精品免费观看二区| 国产精品区一区二区三| 在线不卡欧美| 亚洲在线成人精品| 久久婷婷国产麻豆91天堂| 亚洲国产高潮在线观看| 亚洲精品午夜| 香蕉免费一区二区三区在线观看 | 亚洲综合日韩| 久久国产精品高清| 欧美精品导航| 国产乱理伦片在线观看夜一区| 国产一区二区主播在线| 99国产精品国产精品毛片| 久久精品99| 99re成人精品视频| 久久久欧美精品| 国产精品拍天天在线| 亚洲级视频在线观看免费1级| 午夜精品久久久久久久久久久| 欧美成人资源网| 亚欧美中日韩视频| 欧美日韩大片| 亚洲国产欧美一区| 欧美在线黄色| 亚洲神马久久| 欧美精品一区二区视频| 在线观看成人av电影| 午夜精品久久久久| 99视频精品全国免费| 欧美a级片一区| 精品99一区二区| 欧美一区二区三区免费视| 亚洲三级免费| 欧美www在线| 亚洲第一精品夜夜躁人人躁| 欧美在线观看网站| 亚洲视频一区二区| 欧美日韩免费高清| 宅男66日本亚洲欧美视频| 免费日韩av| 久久精品最新地址| 国产一区二区三区四区老人| 午夜精品一区二区三区电影天堂| 亚洲日本中文字幕区| 你懂的视频一区二区| 亚洲国内自拍| 欧美成人tv| 免费h精品视频在线播放| 国语自产精品视频在线看一大j8| 午夜精品久久久久久久99樱桃| 一区二区三区**美女毛片| 欧美日韩中文在线观看| 亚洲午夜一区二区三区| 一区二区冒白浆视频| 欧美性猛交xxxx乱大交蜜桃| 亚洲无线观看| 亚洲一区999| 国产精品视频不卡| 久久精品国产综合精品| 久久国产欧美日韩精品| 亚洲国产精品免费| 亚洲精品在线观看免费| 国产精品久久影院| 久久婷婷国产综合尤物精品| 裸体女人亚洲精品一区| 99精品视频免费全部在线| 亚洲午夜激情网站| 国内视频精品| 亚洲国产经典视频| 欧美性做爰毛片| 久久久亚洲国产美女国产盗摄| 久久夜精品va视频免费观看| 99国产精品久久久久久久成人热| 中日韩美女免费视频网址在线观看 | 99re66热这里只有精品4| 在线视频日韩| 黄色av日韩| 日韩视频在线观看免费| 国产日韩一区二区三区| 亚洲国产精品成人一区二区| 国产精品白丝av嫩草影院| 久久久久国产精品一区二区| 欧美成人三级在线| 午夜精品久久| 欧美成人精品激情在线观看| 亚洲一级二级在线| 久久久欧美精品sm网站| 亚洲一区二区高清| 卡一卡二国产精品| 亚洲女女女同性video| 麻豆成人在线播放| 久久av老司机精品网站导航 | 国产欧美欧洲在线观看| 欧美电影免费| 国产酒店精品激情| 91久久久久久久久久久久久| 国产欧美精品日韩| 亚洲欧洲在线一区| 樱花yy私人影院亚洲| 一本色道久久综合狠狠躁篇的优点 | 亚洲色图在线视频| 狂野欧美激情性xxxx欧美| 亚洲综合二区| 欧美精品久久久久久久免费观看| 久久久综合网站| 国产欧美一区二区在线观看| 999亚洲国产精| 亚洲精品视频啊美女在线直播| 欧美一二区视频| 亚洲一区免费网站| 欧美日韩另类一区| 亚洲国产成人精品女人久久久| 国产一区在线播放| 亚洲天堂免费观看| 亚洲视频免费| 欧美日韩国产bt| 亚洲全部视频| 一区二区三区av| 欧美人妖另类| 亚洲精品视频在线观看网站| 亚洲日本中文字幕| 欧美激情欧美激情在线五月| 亚洲国产精品免费| 亚洲精品久久| 欧美久久久久久| 亚洲美女毛片| 亚洲影音先锋| 国产精品日韩在线| 亚洲永久免费视频| 久久精品视频免费播放| 国产一级久久| 久久久久在线观看| 欧美大片一区二区| 亚洲国产裸拍裸体视频在线观看乱了| 久久香蕉国产线看观看av| 欧美高清视频免费观看| 亚洲激情电影在线| 欧美激情视频网站| 一区二区三区精密机械公司| 亚洲欧美日韩国产精品| 国产欧美一区二区三区另类精品 | 欧美大片va欧美在线播放| 亚洲日本成人网| 亚洲免费视频一区二区| 国产欧美精品日韩区二区麻豆天美| 亚洲综合精品一区二区| 久久天堂成人| 99视频有精品| 国产精品日韩精品欧美精品| 欧美影院成人| 亚洲人成网站色ww在线| 午夜精品久久久久久久久久久| 国产一区二区三区四区在线观看| 久久亚洲精品中文字幕冲田杏梨| 亚洲激情第一页| 午夜精品久久久久久久99热浪潮| 狠狠88综合久久久久综合网| 欧美激情国产日韩精品一区18| 中文国产成人精品久久一| 久久久久免费观看| 亚洲视频1区| 伊伊综合在线| 国产精品久久久久久久浪潮网站| 久久久久国产精品午夜一区| 亚洲剧情一区二区| 另类尿喷潮videofree| 亚洲一级在线观看| 亚洲第一在线| 国产视频精品va久久久久久| 你懂的一区二区| 午夜欧美理论片| 亚洲毛片在线| 免费亚洲网站| 久久久久国产精品麻豆ai换脸| 亚洲美女淫视频| 尤物九九久久国产精品的特点| 国产精品乱人伦一区二区| 欧美成人精品一区二区| 香蕉成人啪国产精品视频综合网| 亚洲精品久久久久中文字幕欢迎你| 久久婷婷国产综合精品青草| 亚洲欧美日韩在线高清直播| 亚洲美女尤物影院| 亚洲国产精品专区久久| 国产午夜精品视频免费不卡69堂| 欧美三日本三级三级在线播放| 欧美大胆人体视频| 免播放器亚洲一区| 老**午夜毛片一区二区三区| 欧美在线观看视频在线|