C++中const和constexpr關鍵字解析:常量、函數(shù)和指針

很多C++的初學者看到
const
這個關鍵字的第一反應都是一頭霧水,主要是因為const
可以出現(xiàn)在很多的位置,以及后面加入的constexpr
更是常常感到困惑,今天就為大家一一解釋出現(xiàn)它們的含義和以及作用
const關鍵字
const修飾變量
這是最基本的一種用法,顧名思義,就是將該變量修飾為常量,從而不可以修改。很多的全局變量都是通過常量來進行修飾,需要注意的是,使用const
關鍵字修飾的變量需要立刻初始化
// 修飾局部變量,全局變量,成員變量
const int a = 2;
// 錯誤,表達式必須是可修改的左值,意思就是a是個常量,無法修改
a = 3;
// 還有人習慣這種寫法,作用是一樣的,看個人喜好即可
int const b = 22;
// 修飾函數(shù)參數(shù)
void test(const int num) {
? ? ? // 錯誤,表達式必須是可修改的左值,意思就是參數(shù)num是個常量,無法修改
? num = 3;
}
修飾指針
雖然指針也是一種變量,不過當const
與指針出現(xiàn)在一起的時候,位置的不同會發(fā)生不同的作用,所以單獨拎出來講
// 第一種情況:指針常量
int a = 2;
// const作用:使其無法通過指針來修改變量
const int *p = &a;
// 錯誤,表達式必須是可修改的左值
*p = 3;
// 正確
a = 4;
// 4
cout << *p << endl;
// 同樣地,有人習慣這種寫法,作用是一樣的,看個人喜好即可
int const *p2 = &a;
// 第二種情況:常量指針
int a = 2;
// const作用:使指針p無法指向其他變量
int* const p = &a;
int b = 3;
// 錯誤,表達式必須是可修改的左值
p = &b;
修飾函數(shù)
const
用于修飾函數(shù)也是最困惑的地方,主要原因在于它可以出現(xiàn)在不同的地方,并且每一個都有不同的含義。接下來為一一為大家解釋
// 修飾函數(shù)返回值,這種用法毫無意義,它的作用相當于將返回值修飾為了常量,但是返回值是一個將亡值,在返回之后要么賦值給了其他的變量,然后其他變量可以繼續(xù)修改,要么就隨著離開作用域而被釋放內(nèi)存。所以通常不會這么使用。
const int getNum() {
? return 3;
}
// 修飾成員函數(shù),通常加在成員函數(shù)的末尾,作用聲明該成員函數(shù)為只讀函數(shù),即無法修改任何成員變量的值
class Student {
?public:
? void test() const {
? ? ? ? ? ? ? // 錯誤,表達式必須是可修改的左值,因為member是成員變量,而test函數(shù)被const修飾過后無法修改成員變量
? ? ? member = 3;
? ? ? int b = 3;
? ? ? ? ? ? ? // 正確
? ? ? b = 4;
? }
?private:
? int member = 2;
};
const引用
這是const
最常用的一種方式,通常用于函數(shù)的參數(shù)列表中,因為我們知道在C++
中函數(shù)參數(shù)有3中傳遞方式,分別是值傳遞,指針傳遞(或者叫地址傳遞),引用傳遞,前兩種在傳遞時都會發(fā)成拷貝行為
指針本身也是一個變量,在32位操作系統(tǒng)下占用4個字節(jié),64位系統(tǒng)占用8個字節(jié),雖然的拷貝成本會低一點,但是在大量的調(diào)用過程中也比較可觀
所以通常我們采用傳遞引用的方式,因為引用只是變量的一個別名,不占用內(nèi)存,所以不會發(fā)生拷貝行為。但是引用傳遞有一個問題,那就是形參可以改變實參的值。所以為了避免意外修改導致實參的值發(fā)生改,通常會采用const
加上引用的方式傳遞參數(shù)
void test(const Student &s) {
? ...
}
constexpr關鍵字
constexpr
是C++11
中引入的一個關鍵字,它的作用主要是用來修飾一些函數(shù)和變量,使其成為常量表達式,從而在編譯器就可以進行計算,進一步提高程序運行期的效率
??常量表達式:指的是有一個或多個常量組成的表達式,在實際開發(fā)中經(jīng)常會接觸到常量表達式,比如數(shù)組長度就必須是一個常量表達式
// 正確,長度5是由1個常量組成的常量表達式
int arr[5];
// 正確,長度3+4是由2個常量組成的常量表達式
int arr2[3 + 4];
int n = 10;
// 錯誤,長度n是由變量構成,不是常量表達式
int arr3[n];
修飾變量
由此可以看出,只要是常量表達式,我們就可以通過constexpr
來進行修飾,從而提高程序的效率,比如下面這樣
// 正確,2+2是常量表達式,n將會在編譯器進行計算
contexpr int n = 2 + 2;
// 正確,n是一個常量表達式
int arr[n] = {11, 22, 33, 44};
// 33
cout << arr[2] << endl;
修飾普通函數(shù)
constexpr
還可以用于修飾函數(shù)的返回值,在C++11
中被constexpr
修飾的函數(shù)只能是非void類型的函數(shù),而且必須非常簡短,通常只有一句return表達式。不過在后續(xù)的C++14/17/20
標準中進一步的放寬了這了限制,都可以通過編譯了
constexpr int test() {
? return 1 + 1;
}
修飾構造函數(shù)
constexpr
還可以用于修飾自定義類型,不過有一個前提條件,就是該自定義類型具有constexpr
修飾的構造函數(shù),并且該構造函數(shù)不能有具體實現(xiàn),否則會編譯報錯
class Student {
?public:
? constexpr Student(const char* name, int age) : name_(name), age_(age) {}
? void print() const { cout << name_ << ' ' << age_ << '\n'; }
?private:
? const char* name_;
? int age_;
};
void test() {
? constexpr Student s{"zhangsan", 18};
? s.print();
}
總結
??
const
可以修飾編譯期和運行期的常量,而constexpr
只能修飾編譯期的常量??
const
在仍然可以通過const_cast
類型轉換來修改值,而constexpr
是不可以修改的,其實可以將const
理解為只讀變量更符合其含義??
const
只能用于非靜態(tài)成員函數(shù),而constexpr
可以和成員,非成員,構造函數(shù)一起使用??再有常量表示的場景,盡可能的加上
constexpr
來讓編譯期進行計算??但是大面積的
constexpr
也會面臨相應的增加編譯時間的風險