一、 const的作用:
1、限定const指定的值的修改
ex1.1:
const int a = 2;
//a = 3; error: assignment of read-only variable
就如C語言裡宏一樣,a會被放到符號列表裡,不過a是內部鏈接的(內部鏈接是指只在當前文件內是可見的)。當不取a的地址的時候,系統不會給a分配內存,取a地址的時候就會給a分配地址,但改變a指向的內容並不能改變a的值,因為a已經被編譯成為符號了。改變a內存所指內容是沒有任何結果的。
ex1.2:
[cpp]
#include <iostream>
using namespace std;
int main() {
const int ci = 2;
cout<<"the addr of ci is:"<<(&ci)<<endl;
int *p = const_cast<int*>(&ci);
cout<<"the addr of p is:"<<p<<endl;
*p = 5;
cout<<"the value of ci is:"<<ci<<endl;
cout<<"the value of p is:"<<(*p)<<endl;
return 0;
}
輸出結果為:
2、限定函數返回值的修改,限定函數內容的修改
函數返回值加上const,防止賦值運算,member function加上const 限定,防止對象member data修改。
ex1.3:
[cpp]
#include <iostream>
using namespace std;
class Test{
public:
Test();
~Test();
Test& GetTest() {
return *this;
}
const Test& GetConstTest(){
return *this;
}
const Test& operator=(const Test& other) {
this->value_ = other.value_;
return *this;
}
int ChangeValue(int value) const {
//value_ = value; error: value_ is read only
return value_;
}
private:
int value_;
};
int main() {
Test test;
test.GetTest() = test;
//test.GetConstTest() = test; //error can't assignment to return value
return 0;
}
在函數member function GetConstTest() 裡返回值是const屬性的,所以不能為返回值賦值。在ChangeValue裡member function 被限定為const 成員函數,所以在內部不能修改member data value_ 的指。
3、程序的可讀性
加上const限定,可以很清楚的告訴編譯器和程序員,這個數值不可以修改。同時將函數參數定義為const 引用,這樣和傳遞值的感覺是一樣的,防止程序傳遞整個對象。
4、程序的效率
在函數參數的傳遞過程中,變量都是按值拷貝傳遞的,如果是內置類型的話,占用內存空間少,拷貝一下數值無關緊要。但是自定 義類就沒想像的簡單了。在參數傳遞過程中,如果是按值傳遞的話,對象會調用自己的構造函數,並且將整個對象內容拷貝過去,這對於占用內存較多的類還是非常損耗效率的。如果定義為引用或者指針傳遞的話拷貝指針值就可以了。
5、代替部分宏的職責
C語言之所以在發明的時候受到了各方程序員的萬般寵愛,很大一部分原因就是C語言裡的宏。宏不僅可以定義全局數據符號,並且還可以用來構造非常精妙的函數。定義常用的變量,常用的函數非常方便。在方便的同時也有很多問題,比如說沒有類型檢查,只是機械的替換,比如說經典的”Max 宏函數“各種錯誤。看下面的例子。
ex1.4:
[cpp]
#include <iostream>
using namespace std;
#define PI 3.14
#define Log(str) cout<<str<<endl
#define Max(a, b) a > b ? a : b
int main() {
int a = 12;
int b = 5;
int max = Max(a, b);
Log(PI);
Log(max);
Log("hello, world");
return 0;
}
但是通過C++裡的const就能很好的規避一些問題
1、類型檢查
2、名稱沖突,因為宏定義變量是外鏈接的
3、調試代碼效率問題上,如果在宏變量的地方出錯了,編譯器只是將宏變量代替為值,所以當看到對應的值的時候,會非常奇怪這個值是那裡來的,但是對於const變量可以很清楚的知道是那個變量。
二、const的用法
1、限定內置常量
限定常量很簡單,在定義const變量的時候必須初始化,初始化的值可以是常量,也可是變量。
ex2.1:
2、限定指針和引用
指針地址是程序運行的時候為變量分配的內存,所以const指針是不需要初始化的。由於const放的位置不同,對應限制的值也不同。通用的方法就是看const和變量的位置。
[cpp]
int num = 2;
int other = 3;
// assignment
const int* ptr1 = &num
int const* ptr2 = &num
int *const ptr3 = &num
const int* const ptr4 = &num
// change value
ptr1 = &other;
ptr2 = &other;
// ptr3 = &other; // read only error
// ptr4 = &other; // read only error
// *ptr1 = other; // read only error
// *ptr2 = other; // read only error
*ptr3 = other;
// *ptr4 = other; // read only error
3、限定對象
const 在限定對象使用要點:
1、按位限制,對象占用的內存不可改變,將this指針轉為非const指針就可以改變member data。
2、按邏輯限制,對象中的數據成員限制,在const member function 中值申明為mutable 就可以改變。
3、const member data 必須在初始化列表裡初始化完。
4、在class 內部只有char, int, long, float, double可以通過static const 申明的時候賦值。
ex2.3
[cpp]
#include <iostream>
using namespace std;
const int MAX_FRIEND = 100;
class Player{
public:
enum {
boy = 1,
girl = 0
};
Player() : user_id_(0), user_sex_(boy){}
~Player(){}
Player(const Player&);
const Player& operator=(const Player&);
void SetUserId(int user_id);
int GetUserId() const;
void SetGroupId(int group_id) const;
int GetGroupId() const;
void SetUserAge(int user_age) const;
int GetUserAge() const;
void SetUserName(const char* user_name);
void PrintPlayerInfo() const;
private:
int user_id_;
mutable int group_id_;
int user_age_;
string user_name_;
const char user_sex_;
static const int friend_count_ = MAX_FRIEND;
};
Player::Player(const Player& player):user_sex_(boy) {
}
const Player& Player::operator=(const Player& other) {
}
void Player::SetUserId(int user_id) {
user_id_ = user_id;
}
int Player::GetUserId() const {
return user_id_;
}
void Player::SetUserAge(int user_age) const {
const_cast<Player*>(this)->user_age_ = user_age;
}
int Player::GetUserAge() const {
return user_age_;
}
void Player::SetGroupId(int group_id) const {
group_id_ = group_id;
}
int Player::GetGroupId() const {
return group_id_;
}
void Player::SetUserName(const char* user_name) {
user_name_ = user_name;
}
void Player::PrintPlayerInfo() const {
cout<<"user id:\t"<<user_id_<<endl;
cout<<"user name:\t"<<user_name_<<endl;
cout<<"user sex:\t"<<user_sex_<<endl;
cout<<"user age:\t"<<user_age_<<endl;
cout<<"user group:\t"<<group_id_<<endl;
}
int main() {
const Player player1;
//player1.SetUserId(100001);
player1.GetUserId();
Player player2;
player2.SetUserId(100001);
player2.SetGroupId(100);
player2.SetUserAge(21);
player2.SetUserName("Jack");
player2.PrintPlayerInfo();
return 0;
}
通過例子2.3可以看出const objects只能讀取內存的值,不能改寫內存的值。對於const member function,member data group_id_ 是按邏輯申明的可改變變量。而在SetUserAge(int user_age)函數裡通過強轉this指針,來改變member data。
文章裡所示程序在gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)環境裡編譯通過,全文完。
參考:
c++ 編程思想卷一
effective c++ 第三版