const常數與唯讀
const常數
在main()函式之前定義,設定const類型、常數名與值,後面(尾部)有分號;
。
語法
const 類型 常數名 = 值;
int main() {
return 0;
}
1
2
3
4
5
const double PI = 3.14159;
int main() {
cout << PI << endl;
return 0;
}
3.14159
無法修改const
以下程式碼會編譯錯誤,常數不可再被修改。
1
2
3
4
5
6
const double PI = 3.14159;
int main() {
PI = 2.55;
cout << PI << endl;
return 0;
}
無法重覆宣告const
以下程式碼會編譯錯誤,常數不可重覆宣告。
1
2
3
4
5
6
const double PI = 3.14159;
const double PI = 1.666;
int main() {
cout << PI << endl;
return 0;
}
運行階段
const編譯的時候不會有值,只有運行階段才會有值。
以下會編譯錯誤,因為編譯的時候找不到ARR_SIZE的值。
1
2
3
4
5
const ARR_SIZE = 10;
int main() {
int arr[ARR_SIZE];
return 0;
}
使用#define,編譯「前」就會有值,#define的中文叫前置處理,大陸翻譯是預編譯,意思是編譯之前就已經有常數值。
注意!define最後面不能有分號;
,指派10給ARR_SIZE,中間也沒有等號=
。
以下編譯正確。
1
2
3
4
5
#define ARR_SIZE 10
int main() {
int arr[ARR_SIZE];
return 0;
}
const變數
這邊的const不是常數,而是讓變數只能讀,不能修改。
const 變數
代表只能讀取變數,不可修改變數「內容」。
Memory Layout
下圖,有2個變數,分別是i與j,存放在Stack區塊中。
i變數被const修飾,代表這個記憶體位址只能讀取,無法寫入。
j變數,可讀可寫。
SIZE是const全域變數,只能讀取,無法寫入,存在rodata區塊中。
1
2
3
4
5
6
7
8
9
10
11
// const全域常數
const int SIZE = 5;
int main() {
// const 變數
const int i = 10;
// 以下編譯失敗
i = 77; // 不可修改
int j = 55;
j = 66;
return 0;
}
const與函式參數指標
設計一個函式只能讀取參數,但不能修改參數。
以下編譯失敗,因為只能讀取,無法修改參數。
1
2
3
4
5
6
7
8
9
void read_only(const int* p) {
* p = 55; // 這邊編譯失敗,不能修改記憶體位址的內容
cout << * p << endl;
}
int main() {
int i = 55;
read_only(&i);
return 0;
}
const指標與函式參數,無法修改外部位址
之前在const與指標的文件中,提到const指標可以修改記憶體位址。
但在函式參數中,只要是指標,就無法修改記憶體位址。
以下程式,不管change_addr()函式的參數是指標或是const指標,都無法修改main()函式中的i變數記憶體位址。
下圖中,有2個function stack函式堆疊區塊,分別為main()與change_addr()。
change_addr()的x指標,本身的記憶體位址是0x2000,一開始儲存的是0x1000。
執行完以下程式碼,變成0x0500。
1
x = &global_i;
而main()函式的i變數記憶體位址是0x1000,不會被影嚮。
change_addr_const()函式中,const保護的是0x1000的內容只能讀取不能修改。
所以可以修改x指標的位址變成0x0500。
完整程式碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int global_i = 100;
void change_addr(int* x) {
x = &global_i;
printf("chage_addr() i addr = %p \n",x);
}
void change_addr_const(const int* x) {
x = &global_i;
printf("change_addr_const() i addr = %p \n",x);
}
int main() {
int i = 10;
printf("before i addr = %p \n",i);
change_addr(&i);
change_addr_const(&i);
printf("after i addr = %p \n",i);
return 0;
}
before i addr = 0x1000
chage_addr() i addr = 0x2000
change_addr_const() i addr = 0x2008
after i addr = 0x1000
const與物件
以下程式碼,在compare()函式中,參數使用const,代表只能讀取,不能修改。
1
void compare(const Student* s2);
不可以在函式中進行如下操作:
不能修改名字跟分數,編譯錯誤。
1
2
3
4
void compare(const Student* s2) {
s2->name_ = "Alice";
s2->score_ = 100;
}
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Student{
public:
char* name_;
int score_;
Student() {}
Student(char* name, int score): name_(name), score_(score) {}
void compare(const Student* s2) {
if (this->score_ > s2->score_) {
cout << "本身score比較大" << endl;
} else {
cout << "s2 score比較大" << endl;
}
}
};
int main() {
Student s1("Mary", 80);
Student s2("Bill", 90);
s1.compare(&s2);
return 0;
}
const與成員函式
const在函式名()後面,代表的是,無法修改this,this是本身的物件
const放置位置,在函式後面。
傳回值 成員函式(參數) const {
}
以下函式可以修改s2參數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Student{
public:
char* name_;
int score_;
Student() {}
Student(char* name, int score): name_(name), score_(score) {}
void compare(Student* s2) const {
s2->name_ = "Alice";
s2->score_ = 100;
if (this->score_ > s2->score_) {
cout << "本身score比較大" << endl;
} else {
cout << "s2 score比較大" << endl;
}
}
};
int main() {
Student s1("Mary", 80);
Student s2("Bill", 90);
s1.compare(&s2);
printf("s2 name = %s, score = %d\n", s2.name_, s2.score_);
return 0;
}
s2 score比較大
s2 name = Alice, score = 100
以下程式,試圖修改this本身物件的成員變數,會編譯失敗。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Student{
public:
char* name_;
int score_;
Student() {}
Student(char* name, int score): name_(name), score_(score) {}
void compare(Student* s2) const {
this->name_ = "Alice";
this->score_ = 100;
if (this->score_ > s2->score_) {
cout << "本身score比較大" << endl;
} else {
cout << "s2 score比較大" << endl;
}
}
};
int main() {
Student s1("Mary", 80);
Student s2("Bill", 90);
s1.compare(&s2);
printf("s2 name = %s, score = %d\n", s2.name_, s2.score_);
return 0;
}
const與成員變數
成員變數加上const,代表只可以在建構子中,建立物件的時候設定值,之後就不可以修改成員變數了。
以下程式編譯錯誤,因為物件建立完畢,試圖修改分數s1.score_ = 100
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Student{
public:
char* name_;
const int score_; //成員變數加上const
// const成員變數,要在建構子設定初始值
Student(char* name, int score): name_(name), score_(score) {}
};
int main() {
// 一定要在建構子設定成員變數
Student s1("Mary", 80);
Student s2("Bill", 90);
// 不可以再修改成員變數
s1.score_ = 100;
printf("s2 name = %s, score = %d\n", s2.name_, s2.score_);
return 0;
}