C++ const總結

編程中是否遇到這樣狀況?ios

(基本內容來源於C++ Prime)面試

一、用一個變量表示緩衝區的大小。當咱們以爲不合適時,直接改變變量值便可,能夠很方便調整緩衝區大小編程

二、但要警戒程序不當心改變了這個值函數

 

OK,遇到這樣狀況,使用const修飾符便可。spa

 

言簡意賅,總結一下。.net

首先上目錄:設計

一、const對象必須初始化。指針

二、默認狀況下,cosnt對象只在文件內有效code

三、const的引用對象

四、const與指針

五、頂層const 和 底層const

六、C++常量摺疊

七、const函數

八、const成員變量

 

一、const對象必須初始化。

由於const對象一旦建立,就不能改變了。

二、默認狀況下,cosnt對象只在文件內有效

 

下面論述一下const對象和普通對象的區別。

(轉載於http://blog.csdn.net/yipiantiandi/article/details/5822564)

(const對象默認做用域爲:文件做用域)

(普通變量默認做用域:整個程序)

對於通常的對象 如 int a=9;;咱們知道它的做用域是整個程序的,在1.cpp和2.cpp中包含同一個定義了int a=9;的頭文件,由於int a=9;做用域是整個程序,因此會產生錯誤。

那爲何const int a=9;不會產生錯誤呢。緣由就是const int a=9;的默認做用範圍是文件做用域的。即,儘管在1.cpp和2.cpp中包含同一個定義了const int a=9;的頭文件,但因爲const int a=9;是文件做用域的,包含了頭文件的1.cpp和2.cpp儘管都包含了const int a=9;但他們是各自文件內的const對象,二者互不相干,就像不一樣函數中定義了相同的變量名同樣。

 因此,經過在頭文件中定義const對象,能夠實現多個文件使用相同的常量值,這在實際的程序中很常見。

那麼如何使用其餘文件中的const

說到這裏,有一點疑問須要解決:若是想在別的文件中訪問本文件中的const對象該怎麼辦,若是都是單是在別的文件中使用extern const int a = 9;的話,不會起任何做用,由於已經提示const int a = 9;是文件做用域的。

因此應該在須要被其餘文件使用的const對象定義成這樣:extern const int a = 9;而在別的須要使用這個const對象的地方聲明:extern const int a;前者是定義,後者是聲明。這樣就可使用了。

 

三、const的引用

引用前帶const修飾符 被引用前帶const修飾符 附註
對const變量的const引用
引用認爲它引用的變量不能夠改變,但實際能夠(代碼附註1)
不能夠(代碼附註2)
就是普通的引用

 

代碼附註1:

    int i=42;
    const int &r_i = i;
    cout<<"r_i: "<<r_i<<endl;
    cout<<"i:   "<<i<<endl;
    
    i=41;//能夠
    cout<<"r_i: "<<r_i<<endl;
    cout<<"i:   "<<i<<endl;
    
    r_i = 40;//報錯
    cout<<"r_i: "<<r_i<<endl;
    cout<<"i:   "<<i<<endl;

detail it:對const的引用多是引用一個並不是const的對象

 常量引用僅對引用能夠參與的操做作出了限定,對於引用的對象自己是否是常量未作限定。由於對象也多是一個很是量,因此容許經過其餘途徑改變它的值。

 

代碼附註2

    const int r1=42;
    int &r2 = r1;//試圖讓一個很是量引用指向一個常量對象。若是該初始化合法,則能夠經過r2來改變它引用對象的值,這顯然不正確。

 

 

四、const與指針

指針 被指數據 附註
變量 變量 普通的指針
變量 常量 不能夠
常量 變量 能夠。常量指針「自覺得是」,認爲本身指向了常量,因此自覺的不去改變所指對象的值。實際上,這個值是能夠改變的
常量 常量 能夠。

 

Pointer to Constant (常量指針/常指針) Pointer Constant(指針常量)

const int*p1; 

const int x = 1;

p1 = &x; 

int*const p2 = &x;  

p1是一個指針

它是一個常量

p2是一個指針

它指向一個常量

 

 

準則:在前先讀,在前不變 const int *x  int* const y

* (指針)和const(常量)誰在前先讀誰;

* 表明被指的數據,名字表明指針地址

const在誰前面誰就不容許改變。

const在*前面,該數據不能改變 const在地址前面,該地址不能變化
     

 

(此小節內容來自網易公開課,北京郵電大學,崔毅東老師的《C++程序設計入門(上)》)

 

五、由上一節的內容,能夠引伸出一個概念:

頂層const 和 底層const

該對象是const,說明其爲頂層const

該對象指向或者引用的變量是const,說明其爲底層const

const int ci = 42; // 不能改變 ci 的值,這是一個頂層 const

const int *p2 = &ci; // 容許改變 p2 的值,這是一個底層 const

const int *const p3 = p2; // 靠右的 const 是頂層 const ,靠左的是底層 const

 

 六、C++常量摺疊

常量與宏定義一直被面試官津津樂道

轉載於http://blog.csdn.net/yby4769250/article/details/7359278

看個code先,

#define PI 3.14
int main()
{
    const int r = 10;

    int p = pI; //這裏會在預編譯階段產生宏替換,PI直接替換爲3.14,其實就是int p = 3.14;
    int len = 2*r; //這裏會發生常量摺疊,也就是對常量r的引用會替換成他對應的值,至關於int len = 2*10;
    return 0;
}

如上述代碼中所述,常量摺疊表面上的效果和宏替換是同樣的,只是,「效果上是同樣的」,

而二者真正的區別在於,

一、宏是字符常量,在預編譯完宏替換完成後,該宏名字會消失,全部對宏如PI的引用已經所有被替換爲它所對應的值,編譯器固然沒有必要再維護這個符號。

二、而常量摺疊發生的狀況是,對常量的引用所有替換爲該常量如r的值,可是,常量名r並不會消失,編譯器會把他放入到符號表中,同時,會爲該變量分配空間,棧空間或者全局空間

爲了能更清楚的體現出常量摺疊,下面作幾個對照實驗,看代碼和輸出便了然:

int main()
{
    int i0 = 11;

    const int i=0;         //定義常量i
    int *j = (int *) &i;   //看到這裏能對i進行取值,判斷i必而後本身的內存空間
                //請注意,
int *j = &i;是不對的哦,咱們在第4節講過~
    *j=1;                  //對j指向的內存進行修改
    
printf("%d\n%d\n%d\n%d\n",&i,j,i,*j); //觀看實驗效果 const int ck = 9; //這個對照實驗是爲了觀察,對常量ck的引用時,會產生的效果 int ik = ck; int i1 = 5; //這個對照實驗是爲了區別,對常量和變量的引用有什麼區別 int i2 = i1; return 0; }

上面的代碼會輸出:

0012ff7c
0012ff7c

0

1

這能說明什麼,至少能說明兩點:

一、i和j地址相同,指向同一塊空間,i雖然是可摺疊常量,可是,i確實有本身的空間

二、i和j指向同一塊內存,可是*j = 1對內存進行修改後,按道理來講,*j==1,i也應該等於1,而實驗結果確實i實實在在的等於0,這是爲何呢,就是本文所說的內容,i是可摺疊常量,在編譯階段對i的引用已經別替換爲i的值了,也就是說

printf("%d\n%d\n%d\n%d\n",&i,j,i,*j)

中的i已經被替換,其實已經被改成

printf("%d\n%d\n%d\n%d\n",&i,j,0,*j)

爲了使實驗更具說服力,直接上彙編代碼,比較實驗的不一樣點:

4:    int main()
5:    {
00401030   push        ebp
00401031   mov         ebp,esp
00401033   sub         esp,5Ch
00401036   push        ebx
00401037   push        esi
00401038   push        edi
00401039   lea         edi,[ebp-5Ch]
0040103C   mov         ecx,17h
00401041   mov         eax,0CCCCCCCCh
00401046   rep stos    dword ptr [edi]
6:        int i0 = 11;
00401048   mov         dword ptr [ebp-4],0Bh
7:
8:        const int i=0;
0040104F   mov         dword ptr [ebp-8],0 //睜大眼睛,編譯器確實爲常量i分配了棧空間,並賦值爲0
9:        int *j = (int *) &i;
00401056   lea         eax,[ebp-8]
00401059   mov         dword ptr [ebp-0Ch],eax
10:       *j=1;
0040105C   mov         ecx,dword ptr [ebp-0Ch]
0040105F   mov         dword ptr [ecx],1
11:                                            //再看看下面的對比實驗,看出對常量的引用和變量的引用的區別
12:       const int ck = 9;
00401065   mov         dword ptr [ebp-10h],9   //爲常量分配棧空間 
13:       int ik = ck;
0040106C   mov         dword ptr [ebp-14h],9   //看到否,對常量ck的引用,會直接替換爲常量的值9,再看下面的實驗
14:
15:       int i1 = 5;
00401073   mov         dword ptr [ebp-18h],5
16:       int i2 = i1;                         //這裏引用變量i1,對i2進行賦值,而後看到否,對常量i1引用沒有替換成i1的值,而是去棧中先取出i1的值,到edx寄存器中,而後再把值mov到i2所在的內存中
0040107A   mov         edx,dword ptr [ebp-18h]
0040107D   mov         dword ptr [ebp-1Ch],edx
17:
18:
19:       return 0;
00401080   xor         eax,eax
20:
21:   }

 

 

總結:常量摺疊說的是,在編譯階段,對該變量進行值替換,同時,該常量擁有本身的內存空間,並不是像宏定義同樣不分配空間,需澄清這點

 

 

七、const修飾函數

const 放在函數後表示這個函數是常成員函數, 常成員函數是不能改變成員變量值的函數。
const 限定符,它把一個對象轉換成一個常量。

一、很是量成員函數不能被常量成員對象調用,由於它可能企圖修改常量的數據成員:

二、很是量成員函數不能被常量實例調用,由於它可能企圖修改常量的數據成員

 

舉例:
爲了使成員函數的意義更加清楚,咱們可在不改變對象的成員函數的函數原型中加上const說明:
class Point
{
public:
int GetX() const;
int GetY() const;
void SetPt (int, int);
void OffsetPt (int, int);
private:
int xVal, yVal;
};
const成員函數應該在函數原型說明和函數定義中都增長const限定:
int Point::GetY() const
{
return yVal;
}
class Set {
public:
Set (void){ card = 0; }
bool Member(const int) const;
void AddElem(const int);

};
bool Set::Member (const int elem) const
{
}
很是量成員函數不能被常量成員對象調用,由於它可能企圖修改常量的數據成員:
const Set s;
s.AddElem(10); // 非法: AddElem不是常量成員函數
s.Member(10); // 正確
 
 
八、const成員變量
#include <iostream>
using namespace std;

class A
{
    public:
        A(int size) : SIZE(size) {};
    private:
        const int SIZE;
};

int main()
{
    A a(100);
}
  • 在類中聲明變量爲const類型,可是不能夠初始化
  • const常量的初始化必須在構造函數初始化列表中初始化,而不能夠在構造函數函數體內初始化

此時的const變量屬於具體的一個對象,如何在整個類中都恆定不變呢?

 答案是利用枚舉,舉例

#include <iostream>
using namespace std;

class A
{
    private:
        enum {SIZE = 100};
    public:
        int array[SIZE];
};

int main()
{
    A a;
}

枚舉常量不會佔據對象的存儲空間,在編譯時被所有求值

可是,它隱含的數據對象類型爲整形,不能表示其餘類型。

相關文章
相關標籤/搜索