文章目錄
- 一、C++中的const如何理解?
- 二、C++中的const與C語言中的const有何區別?
- 三、const與指針、引用的結合使用
一、C++中的const如何理解?
在C++中,const是一個關鍵字,用來表示常量性,意在告訴編譯器某些變量或對象的值是不可修改的,從而提高代碼的安全性和可讀性。
二、C++中的const與C語言中的const有何區別?
1. 語義層面的不同
在C語言中,const更多地是一個承諾,它表示變量在當前作用域中不能被修改,但這種約束不是絕對的,可以通過特定的方式繞過,例如強制類型轉換。
在C++中,const語義更加嚴格和完善。它不僅約束變量,還能作用于成員函數、引用、指針等,且配合C++的類型系統,實現了更強的編譯時檢查。
2. const與引用
在C語言中沒有引用的概念,因此const無法結合引用使用。
C++支持常量引用,用來避免拷貝,提高效率,同時保護原始數據不被修改。
void func(const int& ref) {// ref 是只讀的,不能修改原始值
}
這種用法在C++中非常常見,特別是在傳遞大型對象時。
3. 修飾函數
C語言沒有成員函數的概念,因此const無法作用于函數級別。
C++允許const修飾成員函數,表示該函數不會修改對象的狀態。這種語義在面向對象編程中非常重要。
class MyClass {
public:void display() const { /* 不會修改成員變量 */ }
};
4.繞過const的方式
C語言可以通過強制類型轉換((int*))來繞過const的限制。在C語言中const修飾的變量,可以不用初始化,它不叫常量,而是叫常變量。
const int a = 20;
int *p = (int*)&a;
*p = 30;
printf("%d %d %d\n", a, *p, *(&a));
輸出結果:30 30 30
雖然C++也支持強制類型轉換,但C++提供了更安全的const_cast,明確表示是移除const限定符。
const int a = 10;
int* p = const_cast<int*>(&a);
*p = 20; // 合法,但可能導致未定義行為
5.編譯方式不同
在C語言中const就是被當作一個變量來編譯生成指令的。
在C++中,所有出現const常量名字的地方,在編譯時都被常量的初始化值替換了。且不能作為左值。
在C++中const用字面常量去初始化,如:
int main() {const int a = 20;//a是使用立即數進行的初始化,所以a為常量int array[a] = {};int* p = (int*)&a;*p = 30;std::cout << a << "," << *p << std::endl;return 0;
}
輸出結果:20,30
在C++中const用變量去初始化,如:
int main() {int b = 20;const int a = b;//a的初始值不是立即數,是一個變量,所以a此時為常變量//int array[a] = {}; //無法使用變量初始化數組int* p = (int*)&a;*p = 30;std::cout << a << "," << *p << std::endl;return 0;
}
輸出結果:30,30
三、const與指針、引用的結合使用
const修飾的變量常出現的錯誤是:
常量不能作為左值(不能直接修改常量的值)。
不能把常量的地址泄露給一個普通指針或者普通的引用變量(不能間接修改常量的值)。
int main() {const int a = 10;int b = 20;a = b; //錯誤:常量a不能再作為左值,表達式必須是可修改的左值int* p = &a; //錯誤: 不能將const int* 轉換為int*,這樣就會間接修改a的值return 0;
}
1.const和一級指針的結合
注意:const修飾的是離它最近的類型
const int *p:const離int最近,所以修飾的是int類型,而const修飾的表達式是*p,這個時候就不能再修改*p的值,即指針的指向不能再做修改(指針的指向是常量),但是指針的本身是可以被修改的,比如p = &b。換句話說就是p可以指向不同的int類型的內存,但是不能通過指針間接修改指向的內存的值。
int const *p:const離int最近,修飾的是int類型,所以const修飾的表達式是*p,作用同上。
int *const p:const離int*最近,修飾的是int*類型,所以const修飾的是p本身。即這個指針的本身是常量,所以一旦p初始化指向某塊內存,那么就不能再更改它的指向。但是可以通過指針解引用修改指向的內存的值。
const int *const p:其作用是const int *p與int *const p的結合。
int main() {int* q1 = nullptr;int* const q2 = nullptr;std::cout << typeid(q1).name() << std::endl;std::cout << typeid(q2).name() << std::endl;// const如果右邊沒有指針*的話,const是不參與類型的// 比如說下面的const p3,表明p3是一個常量,即指針的指向不能再做改變int a = 10;int* p1 = &a;const int* p2 = &a; // const int* 轉換為 int*int* const p3 = &a; // int* 轉換為 int*int* p4 = p3; //int* 轉換為 int*return 0;
}
2.const和二級指針的結合
const和二級指針結合的幾種方式
const int**q:const修飾的類型是int,而它修飾的表達式是**q,所以**q不能被賦值,但是*q可以被賦值,q本身可以被賦值。
int *const *q:const修飾的類型是int *,而它修飾的表達式是const *q,所以*q不能被賦值,但是**q可以被賦值,q本身也可以被賦值。
int ** const q:const修飾的類型是int**,而它修飾的表達式是q,所以q本身不能被賦值,但是*q和**q可以被賦值。
3.總結const和指針的類型轉換公式
int* 轉換為 const int* 是不可行的。
const int* 轉換為 int* 是可行的。
int ** 轉換為 const int** 是不可行的。
const int** 轉換為 int **是不可行的。
int** 轉換為int* const*是錯誤的。
int* const*轉換為int**是可行的
4.const和一級指針,引用的結合使用
//寫一句代碼:在內存的0x0018ff44處寫一個4字節的10
int *p = (int*)0x0018ff44;
int *const &p1 = (int*)0x0018ff44; //(非常量引用的初始值必須為左值)0x0018ff44已經為常量了,如果使用引用,需要使用const修飾
int *&&p2 = (int*)0x0018ff44; //也可以使用右值引用(什么是右值:沒內存,沒名字,即字面常量)
飾