編譯器將在編譯過程中把用到const變量的地方都替換成對應的值,為了執行這種替換,編譯器必須知道變量的初始值。如果程序包含多個文件,則那個用了const對象的文件都必須能訪問到它的初始值才行。要做到這一點,就必須在每一個用到變量的文件中都有對它的定義。為了支持這一用法,同時避免對同一變量的重復定義,默認情況下,const對象被設定為僅在文件內有效。當多個文件中出現了同名的const變量時,其實等同於在不同文件中分別定義了獨立的變量。
某些時候有這樣一種const變量,它的初始值不是一個常量表達式,但又確實有必要在文件間共享。在這種情況下,我們不希望編譯器為每個文件分別生成獨立的變量。相反,我們想讓這類const對象像其他(非常量)對象一樣工作,也就是說,只在一個文件種定義cons,而在其他多個文件中聲明並使用它。
解決的辦法是,對於const變量不管是聲明還是定義都添加extern關鍵字,這樣只需定義一次就可以了:
// file_1.cc定義並初始化了一個常量,該常量能被其他文件訪問 extern const int bufsize = fcn(); // file_1.h頭文件 extern const int bufsize;//與file_1.cc中定義的bufsize是同一個
因為bufsize是一個常量,必須用extern加以限定使其被其他文件使用。
file_1.h頭文件中的聲明也由extern做了限定其作用是指明bufsize並非本文件所獨有,它的定義將在別處出現。
如果想在多個文件之間共享const對象,必須在變量的定義之前添加extern關鍵字。
const double *cptr;指向常量的指針。不能用於改變其所指對象的值,可指向非常量的對象,所謂指向常量的指針僅僅要求不能通過該指針改變對象的值,而沒有規定那個對象的值不能通過其他途徑改變,
double const *cptr;常量指針,即不變的是指針本身的值而不是指針指向的那個值。
用頂層const 表示指針本身是個常量,用底層const 表示指針所指的對象是一個常量。
const int *const p3=p2;//靠右的const是頂層const,靠左的是底層const
constexpr和常量表達式
常量表達式(const expression)是指值不會改變並且在編譯過程中就能得到計算結果的表達式。一個對象(或表達式)是不是常量表達式由它的數據類型和初始值共同決定,例如:
const int max=20;//max是常量表達式 const int li=max+1;//li是常量表達式 int sta=27;//sta不是常量表達式 const int sz=get();//sz不是常量表達式
盡管sz本身是一個常量,但它的具體值知道運行時才能獲取到,所以也不是常量表達式。
constexpr變量
constexpr類型將由編譯器來驗證變量的值是否是一個常量表達式。聲明為constexpr的變量一定是一個常量,而且必須用常量表達式初始化:
constexpr int mf=20;//20是常量表達式 constexpr int li=mf+1;//mf+1是常量表達式 constexpr int sz=size();//只有當size是一個constexpr函數時才是一條正確的聲明語句
如果認定變量是常量表達式,那就把它聲明成constexpr類型,只有字面值類型才能定義成constexpr。
到目前為止接觸過的數據類型中,算術類型、引用和指針都屬於字面值類型,IO庫,string類型則不屬於字面值類型,也就不能被定義成constexpr
盡管指針和引用都能定義成constexpr,但它們的初始值卻受到嚴格限制,一個constexpr指針的初始值必須是nullptr或者0,或者是存儲於某個固定地址中的對象。
constexpr指針不能指向函數體內定義的變量(因為一般來說並非存放在固定地址中)。
定義於所有函數體之外的對象其地址固定不變,能用來初始化constecpr指針。
指針和constexpr
在constexpr聲明中如果定義了一個指針,限定符僅對指針有效,於指針所指的對象無關;
constexpr指針既可以指向常量也可以指向一個非常量。