1. 取代#define 進(jìn)行值替代
2. 修飾指針
3. 修飾參數(shù)和返回值
4. 修飾類和類成員變量及類成員函數(shù)
一、值替代 #define只在預(yù)處理器進(jìn)行值替代,并且沒有類型標(biāo)識(shí),出現(xiàn)錯(cuò)誤很難排查。const 提供類型信息,在編譯期可以進(jìn)行類型檢查。編譯器在編譯時(shí)可以通過必要的運(yùn)算把一個(gè)復(fù)雜的常量表達(dá)式簡化,稱為常量折疊。
我理解的常量折疊是:編譯器會(huì)把這個(gè)常量放到一個(gè)符號(hào)表中,比如說const int i = 1;符號(hào)表中有一個(gè)符號(hào)i,同時(shí)對應(yīng)了一個(gè)數(shù)值1,此時(shí)是不分配內(nèi)存空間的。如果你強(qiáng)行分配內(nèi)存空間的話也可以。
const int i = 1;
int* ip = const_cast<int*>(&i);
*ip = 2;
cout <<"i = "<<i ;
cout <<"*ip = "<< *ip;
cout <<"*(&i) = "<<*(&i) ;
// i = 1;
//*ip = 2;
//
*(&i) = 1;
不論你怎么通過內(nèi)存修改i,看起來i有兩個(gè)值,1和2,這貌似就是常量折疊。
內(nèi)部鏈接問題 C++中的const是內(nèi)部鏈接,即const僅在被定義過的文件中才是可見的,鏈接時(shí)不能被其他編譯單元看到。在定義時(shí),必須賦一個(gè)初值,不然必須用extern顯式地聲明。
通常,編譯器是不為const創(chuàng)建存儲(chǔ)空間的,相反把這個(gè)定義保存在它的符號(hào)表中。但是extern強(qiáng)制執(zhí)行了存儲(chǔ)空間的分配,因?yàn)閑xtern表示使用外部鏈接,也就是有幾個(gè)不同的編譯單元可以引用它,所以必須有存儲(chǔ)空間。(這句話我的理解是:每個(gè)編譯單元都有自己的符號(hào)表,其他編譯單元是不能看到其他編譯單元符號(hào)表中的東西的。其他編譯單元如果要引用一個(gè)外部變量,該變量必須是在內(nèi)存中,可以讀取的。所以一定要分配空間。外部鏈接一般是找到相應(yīng)名字的內(nèi)存地址,比如鏈接一個(gè)外部函數(shù),就是找到這個(gè)函數(shù)的內(nèi)存地址)
通常沒有extern的時(shí)候,不會(huì)分配存儲(chǔ)空間。但是有些結(jié)構(gòu)比較復(fù)雜的const,編譯器還是會(huì)分配空間。因?yàn)?h文件中一般放置的都是不分配空間的代碼,所以cosnt變量默認(rèn)為內(nèi)部鏈接。不然鏈接程序在多個(gè)目標(biāo)文件中看到相同的定義就會(huì)”抱怨“。
用常量表達(dá)式定義數(shù)組大小 定義數(shù)組的大小的時(shí)候,必須是常量表達(dá)式,不能為變量,至于為什么。不太清楚,只是編譯器在編譯的時(shí)候給出錯(cuò)誤:期望一個(gè)常量表達(dá)式,不能分配一個(gè)長度是0的數(shù)組,變量是長度未知的。(我的理解是,因?yàn)樽兞渴亲兊模绻o態(tài)地聲明了一個(gè)數(shù)組a[b]因?yàn)椋獯_定,定義的時(shí)候b是1,在之后又被修改為2,那數(shù)組a長度到底應(yīng)該是1呢還是2呢?)
常量表達(dá)式:
const int i = 100;// constant
const int j = 100 + i;// constant express
long addr = (long)&j;// forces storage
char buf[j + 10];//right
const可以應(yīng)用于集合,但是編譯器不會(huì)把一個(gè)集合保存到符號(hào)表中,所以必須分配內(nèi)存。這種情況下,const意味著‘不能改變的一塊內(nèi)存’,編譯器不需要知道里面存儲(chǔ)的內(nèi)容。如果這樣理解的話,那么編譯器在看到int b = 1;這句話的時(shí)候,也會(huì)想”這是一個(gè)int型的變量,我給他分配2個(gè)字節(jié)就行了,里面是什么,或許要到運(yùn)行的時(shí)候再說了“,所以a[b]的長度就是未知長度了。
二、const 指針和指向const的指針 int* u, v;== int*u; int v;
因?yàn)椋悖珜︻愋蜋z查非常精細(xì),所以,你可以把一個(gè)非const指針賦給const指針,但是不能把一個(gè)const指針賦給非cosnt指針。同樣也不能把指向const的指針賦給指向非const的指針
int d = 1;
const int e = 2;
int* u = &d;//right;
int* v = &e;//wrong
int* w = const_cast<int*>(&e);//right
int* y = (int*)&e;//right
考慮下面一句代碼:
char* cp = "howdy";
”howdy"是存放在字符常量區(qū)的,它是個(gè)常量,這個(gè)表達(dá)式返回的是一個(gè)const char*,但是在某些編譯器中是可以通過編譯的。但最好寫成const char* cp = "howdy";修改該字符串?dāng)?shù)組是錯(cuò)誤的。如果想修改它就把它放到一個(gè)數(shù)組中char cp[] = "howdy";為什么呢?
char cp[] = "abcd";
cp[1] = '2';
cout <<cp << endl;
// legall
char *cp = "abcd";
cp[1] = '2';
cout << cp << endl;//cause runtime error
第一種情況:"abcd"是放在字符常量區(qū)的,但是數(shù)組是放在棧上的,現(xiàn)在棧上有5個(gè)字節(jié)的數(shù)組,分別存放了'a','b','c','d''/0',所以你修改它沒問題。第二種:"abcd"是放在字符常量區(qū)的,cp只是一個(gè)指針,指向了這串字符串,想修改它是錯(cuò)誤地。臨時(shí)量 他們也需要存儲(chǔ)空間,并且可以構(gòu)造和銷毀,但是,我們看不到它們,并且自動(dòng)地成為常量。一旦計(jì)算結(jié)束,臨時(shí)變量也會(huì)不復(fù)存在,所以對臨時(shí)變量所做的任何操作都會(huì)丟失。
傳遞指針和引用的時(shí)候一般都用const修飾。
值拷貝:
int i = 1;
int* const ip = &i;
int* ip2 = ip;//right;because you can't modify ip by ip2
const int j = 2;
int k = j;//right;// you can't modify j by k;
const int m = 1;
int* mp = &m;//wrong, you can modify m by mp, but m is a constant
類中的const非static變量在構(gòu)造函數(shù)的初始化列表里定義
static const 在定義的地方初始化,enum可以實(shí)現(xiàn)static const作用
class A
{
enum {size = 100};
int i[size];
};//equal to static const int size = 100;
const對象const A a(1); 必須保證對象的數(shù)據(jù)成員在其聲明周期中不被改變。如何保證?用const成員函數(shù),明確表示不改變成員數(shù)據(jù)。聲明的時(shí)候要用const 定義時(shí)也要用const,不然會(huì)被看作兩個(gè)函數(shù)。
class X
{
int i;
public:
int f() const;
};
int X::f() const
{
return i;
}
按位const和按邏輯const按位是指這塊內(nèi)存中的每個(gè)字節(jié)都是不能改變的。
按邏輯是指,可以在某個(gè)成員函數(shù)中修改成員變量。兩種方法:
class X
{
int i;
public:
void f() const;
}
void X::f() const
{
(const_cast<X*>(this))->i++;//right
}
void X::f(const X* this)
{
this->i++;//illegal
(const_cast<X*>(this))->i++;//right
}
//////////another method//////////
class X
{
mutable int i;
public:
void f() const;
}
void X::f() const
{
i++;//right
}
posted on 2012-05-30 16:12
Dino-Tech 閱讀(164)
評(píng)論(0) 編輯 收藏 引用