前言
前一篇文章我們主要介紹了C++中的復合類型引用和指針,這篇文章我們將會主要介紹C++中const關鍵字。有時候我們想定義一個值不能被改變的變量,例如我們想使用一個變量存儲buffer的大小,如果我們不希望這個值被改變,那么我們就可以使用const關鍵字。
const int bufSize = 512;
現在已經定義了一個const變量bufSize,如果想對const變量賦值就會報錯
bufSize = 256 //會報錯
const初始化
因為在我們創建一個const對象后就沒有辦法改變const對象的值,所以其必須被初始化。
const int j = get_size(); //可以運行時初始化
const int i = 42; //可以在編譯時初始化
const int k; //錯誤,k沒有被初始化
正如之前我們多次提到的,一個對象的類型決定來其所有支持的操作,一個const類型可以使用絕大多數并不是全部非const類型的操作,唯一的限制就是我們使用的操作不能改變const對象的值,例如我們可以在算術表達式中將const類型的變量當作非const類型的變量使用,因為其沒有改變const變量的值。
當一個const對象在編譯期間就被一個常量初始化了,例如我們上述例子提到的bufSize在編譯期間就被初始化為512,在編譯期間編譯器就會將所有使用到bufSize的地方替換為512。為了替換變量的值,編譯器必須要知道變量的初始化結果,為了知道初始化結果,所有需要使用該變量的文件都需要定義該變量,為了支持這種用法,同時避免定義多個相同的變量,const變量對于文件來說是本地的,當我們定義在不同的文件中定義多個同名的const變量,它們表現起來就像我們在不同的文件定義了不同的變量。
但是有時候我們希望在不同的文件中共享同一個const變量,但是其初始化并不是一個常量,我們并不希望編譯器為每一個文件生成單獨的變量,而是希望想非const變量一樣,我們希望在一個文件定義,然后在另一個文件聲明且使用該const變量,這時候就要使用extern關鍵字
//file1.cc定義切初始化了一個const變量
extern const int bufSize = fcn();
//file1.h
extern const int bufSize;
指向常量的引用
正如其他的對象,我們也可以將一個引用綁定到一個const類型的對象,為此我們可以使用一個引用指向,不同于一般的引用,一個指向常量的引用無法改變該引用指向的對象,這也很好理解,因為該對象是一個常量,而常量一旦定義就無法更改。
const int ci = 1024;
const int &r1 = ci; //正確,引用和引用指向的對象都是常量
r1 = 42; //錯誤,r1指向的是一個常量,無法改變一個常量的值
int &r2 = ci; //錯誤,無法讓一個非常量的引用指向一個常量
?一些開發這習慣于將指向常量的引用簡稱為常量引用,這個簡稱看上去說的通,但是你需要記住這就是個簡稱,從技術的角度來說是沒有常量引用的,因為一個引用不是一個對象,所以我們無法讓一個引用本身是一個常量。
?
指向常量的引用未必指向一個常量
從之前的例子中我們可以看到指向一個常量的引用必須是一個常量引用,否則會報錯,但是一個指向常量的引用不一定指向一個常量,只是不同通過該引用來改變該對象的值,這么說可能有點繞,可以用以下例子說明
int i = 42;
int &r1 = i; //r1是指向i的引用
const int &r2 = i; //r2是指向i的常量引用,但是不能通過r2改變i的值
r1 = 0; //r1是非常量引用,可以通過r1改變i的值
r2 = 0; //r2是常量引用,無法通過r2改變i的值
指針與常量
與引用相同,指針可以指向常量也可以指向非常量,同樣指向常量的指針無法通過該指針來改變所指向的常量的值。
const double pi = 3.14; \\\\pi是一個常量,其值不可以改變
double *ptr = π //錯誤 ptr不是一個指向常量的指針,所以無法指向pi
const double *cptr = π //正確,cptr是指向常量的指針
*cptr = 42; //錯誤,cptr指向的是常量,其值無法改變
還是與引用相同,我們也可以讓一個指向常量的指針指向一個非常量,但是不可以通過該指針改變該對象的值
double dval = 3.14;
cptr = &dval; //正確,但是無法通過cptr改變dval的值
常量指針
與引用不同,指針本身是一個對象,所以其本身可以是常量,常量指針與其他的常量性質是相同的,常量指針必須初始化,且一旦初始化該指針持有的地址也將不會改變,那么該如何聲明一個指針呢,那就是在*后加上const,例子如下
int errNumb = 0;
int *const curErr = &errNumb; //curErr是一個常量指針,將會一直指向errNumb
const double pi = 3.1425926;
const double *const pip = π //pip是一個常量指針且指向一個常量
常量表達式
常量表達式是指其返回值在編譯階段就能計算出來且不會改變的表達式,一個對象是否是常量表達式取決于其類型和初始化結果,例子如下
const int max_files = 20; //是
const int limit = max_files; //是
int staff_size = 27; //不是,因為其類型不是const
const int sz = get_size(); //不是,因為get_size()需要在運行時才能計算出來
constexpr
在一個大型的系統中有時候我們很難去確定初始化的結果是否是常量表達式,也許我們定義來一個常量并且用一個我們以為的常量表達式去初始化,但是一些場景下我們需要一個常量表達式但是最后返回不是一個常量表達式,那么一個對象在定義和使用的情況并不一致。在新標準下為了解決這個問題,提供了constexpr關鍵字,如果一個變量被constexpr修飾,那么編譯器將會檢查該變量是否是一個常量表達式。
constexpr int mf = 20; //20是常量表達式
constexpr int limit = mf + 1; //mf + 1是常量表達式
constexpr int sz = size(); //正確,如果size constexpr函數,這個之后文章會介紹
指針與constexpr
需要注意的是如果我們定義一個指針在constexpr表達式中,那么constexpr是作用于指針,而不是指針指向的值。
const int *p = nullptr; //p是一個指向常量的指針
constexpr int *q = nullptr; //q是一個常量指針
constexpr const int *cptr = nullptr; //cptr是一個常量指針,且指向一個常量
-
buffer
+關注
關注
2文章
120瀏覽量
30130 -
C++
+關注
關注
22文章
2114瀏覽量
73857 -
CONST
+關注
關注
0文章
45瀏覽量
8187
發布評論請先 登錄
相關推薦
評論