一、c和c++區別
c語言const的特點:
1.c語言中const變量是隻讀的,本質還是變量
2.const修飾的變量在棧上分配空間
3.const修飾的全局變量在只讀存儲區分配空間
4.const只在編譯期有用,運行期無用
總結:const修飾的變量不是真的常量,只是告訴編譯器該變量不能出現在賦值符號的左邊
c++中const在c的基礎上進行了升級
1.當碰到const聲明時,將常量納入符號表
2.編譯期如果發現使用常量,直接用符號表中的值進行替換
3.編譯器若發現一下情況則給對應的常量分配存儲空間
·對const使用extern
·對const使用&操作符
c++中const與宏的區別
1.const常量由編譯器處理
2.編譯器對const常量進行類型檢查和作用域檢查
3.宏由預處理處理,只是單純的文本替換
關於c++中const&分配存儲空間的代碼
void test_const(){
const int a = 3;
int *p = (int *)&a;
*p = 5;
cout << "a = " << a << endl;
cout << "*p = " << *p << endl;
cout << "&a = " << &a << endl;
cout << "p = " << p << endl;
}
輸出:
a = 3
*p = 5
&a = 0x7ffeec3a8a3c
p = 0x7ffeec3a8a3c
發現a的值爲3,但是*p的值是5,驗證了之前說的符號表中的值進行替換,而第二行用到了&a對a又分配了空間,*p則是改變了分配的空間的值
二、const修飾符的使用
1.const與指針的搭配
int a = 2, b = 3;
int * const p1 = &a;
const int * p2 = &a;
*p1 = 3; // 正常賦值
p1 = &b; // 報錯,指針指向不能改變
*p2 = 3; // 報錯,指針指向的值不能改變
p2 = &b; // 正常修改指針指向
2.const成員函數
·const對象調用
·不允許修改任何non-static成員變量
·常量性不同,可以進行重載
下面引用effective C++裏面的例子
class TextBlock{
public:
TextBlock(string text):text(text){
}
const char& operator[](std::size_t pos) const{ // operator[] for const對象
return text[pos];
}
char& operator[](std::size_t pos) { // operator[] for non-const對象
return text[pos];
}
void setText(std::string text) const{
this->text = text;
}
private:
std::string text;
};
int main(){
TextBlock tb("hello");
const TextBlock tcb("world");
std::cout << tb[0];
std::cout << tcb[0];
tb[0]='x'; // 正常賦值
tcb[0]='x'; // 編譯錯誤,返回的是const
tb.setText("abc"); // 編譯錯誤,no viable overloaded '=' 將const去掉正常賦值
return 0;
}
1.const對象調用的是const聲明的成員函數,
2.這裏面兩個函數都返回都是char&,如果返回都是char,那麼也同樣無法通過編譯(原因是如果函數返回值是內置類型,那麼改動返回值不合法,即使合法,也是一個副本,也不是你想要的結果)
3.setText方法設置成const則該成員函數不能修改任何non-static成員變量
有些時候,必須使用const成員避免一些莫名其妙的問題如:(a*b) = c;
class Complex{
public:
Complex(int real, int imag):real(real),imag(imag){
}
const Complex operator*(const Complex& comp1){
Complex c(0,0);
c.real = this->real * comp1.real - this->imag*comp1.imag;
c.imag = this->real * comp1.imag + this->imag * comp1.real;
return c;
}
void show(){
cout << this->real << " + " << this->imag << "i" << endl;
}
private:
int real;
int imag;
};
int main(){
Complex c1(2,3);
Complex c2(3,2);
Complex c3 = c1*c2;
c3.show();
Complex c4(1,1);
(c1*c2) = c4;
return 0;
}
(c1*c2) = c4這種代碼不應該出現,但是編譯器如果重載操作符opertor*不返回一個const的話,那麼這種不合理現象只能在運行期發現,加上const則在編譯器就能發現
3.const修飾函數參數
當函數參數爲const的引用的時候,會創建臨時變量:
·實參類型正確,但是不是左值
·實參類型不正確,但是可以轉換成正確的類型
借用c++ primer plus例子
double refcube(const double &ra){
return ra*ra*ra;
}
double side = 3.0;
double * pd = &side;
double & rd = side;
long edge = 5l;
double lens[4] = {2.0,5.0,10.0,2.2};
double c1 = refcube(side); // 類型正確,左值
double c2 = refcube(lens[2]); // 類型正確,左值
double c3 = refcube(rd); // 類型正確,左值
double c4 = refcube(*pd); // 類型正確,左值
double c5 = refcube(edge); // 類型不正確,ra是一個臨時變量
double c6 = refcube(7.0); // 類型正確,不是左值,ra是一個臨時變量
double c7 = refcube(side+7.0); // 類型正確,不是左值,ra是一個臨時變量
解釋下,左值是可以被引用的值,例如:變量,數組,結構成員,引用,解除引用的指針都是左值,非左值包括字面量,和包含多項的表達式
正常情況下,接受引用參數的函數的意圖是修改作爲參數傳遞的變量,如果創建臨時變量,則在函數體內修改,並不能改變原來的變量,顯然這不是開發者的意圖,c++在沒有const的情況下就是這麼做的,去掉const發現編譯器報錯。但是現在refcube函數傳遞的變量只是使用值,所以臨時變量並不影響
引用參數聲明爲const理由有三個:
·避免無意中修改數據的編程錯誤
·使用const能處理const和non-const參數,否則只能接受non-const參數
·是函數能正確生成並使用臨時變量