1.定義程序中頻繁使用的常量
#include <iostream>
using namespace std;
const double PI=3.1415926;
int main()
{
cout<<"圓的面積是:"<<PI*3*3<<endl;
cout<<"周長是:"<<2*PI*3<<endl;
return 0;
}
和define定義宏相比,這個具有運行時檢驗且是類型安全的。
2.用在類成員之前修飾:
#include <iostream>
using namespace std;
class Test
{
private:
const int i;//注意這個是對象生命期內保持值不變
public:
Test(int ii):i(ii){}
void demo();
void error();//error
};
void Test::demo()
{
cout<<i*i<<endl;
}
void Test::error()
{
i=0;//error:不能修改只讀成員
}
int main()
{
Test t1(10);
t1.demo();
Test t2(50);
t2.demo();
return 0;
}
這種const為我們提供了一種,為對象提供只讀屬性的方式,注意,const的成員是在成員初始化列表裡初始化的。
3.如果是類的所有實例對象共用的常量,那麼如下:
#include <iostream>
using namespace std;
class Test
{
private:
static const int i=100;//所有類實例共用
public:
Test(){};
void demo();
};
void Test::demo()
{
cout<<i<<endl;
}
int main()
{
Test t1;
t1.demo();//100
Test t2;
t2.demo();//100
return 0;
}
注意這裡初始化在定義處。
4.const和指針結合使用
#include <iostream>
using namespace std;
int main()
{
int a=123;
const int *p=&a;
cout<<*p<<endl;
*p=456;//error:不能修改p執行的內存
return 0;
}
這裡我們發現p指向的內容是不允許修改的,是只讀的。
於是這裡可看作p指向的類型是"const int"的,換句話說*p是個const int是不可變,當然並沒有const int的類型。
我們交換下int和const:
#include <iostream>
using namespace std;
int main()
{
int a=123;
int const *p=&a;
cout<<*p<<endl;
*p=456;//error:不能修改p執行的內存
return 0;
}
發現和上面一樣,之所以這樣是因為我們怎麼改都是,處在*的左側,改變不了p指向(*可以理解為指向)的數據是個int const的,不可變的。
好那就放在*右面
#include <iostream>
using namespace std;
int main()
{
int a=123;
int* const p=&a;
cout<<*p<<endl;//123
*p=456;
cout<<a<<endl;//456
return 0;
}
現在是const p指向一個int類型的數據,這裡const修飾的是指針p.
所以說是p的值不允許改變。
如:
#include <iostream>
using namespace std;
int main()
{
int a=123;
int b=789;
int* const p=&a;
cout<<*p<<endl;//123
*p=456;
cout<<a<<endl;//456
p=&b;//error:p不允許修改,只讀指針
return 0;
}
自然而然的大家就能理解下面的代碼了:
#include <iostream>
using namespace std;
int main()
{
int a=123;
int b=789;
const int* const p=&a;
cout<<*p<<endl;//123
*p=456;//error
p=&b;//error
return 0;
}
5.const結合引用
引用大家可能不陌生
#include <iostream>
using namespace std;
int main()
{
int a=123;
int &b=a;
b=456;//b可以看作是a的別名,指向同一個內存
cout<<a;//456
return 0;
}
有點像const指針:
比較下
#include <iostream>
using namespace std;
int main()
{
int a=123;
int &b=a;
b=456;//b可以看作是a的別名,指向同一個內存
int* const c=&a;
*c=789;
cout<<a;//789
return 0;
}
不過引用因此了指針存儲地址的特性,比較隱蔽,看作別名,在c++中可是大行其道啊。常常使用。
注意:引用定義時需要初始化,而且之後不能再引用其他變量。
看一下const和引用使用:
#include <iostream>
using namespace std;
int main()
{
int a=123;
const int &b=a;
//b=456;//error:b引用的地方不可以修改
a=456;//不過通過a是可以修改的,只是說不能由b修改
return 0;
}
6.const與函數
看看這個
#include <iostream>
using namespace std;
void f(int i)
{
cout<<i*i<<endl;
}
int main()
{
int a=11;
f(a);//121
return 0;
}
這裡我們的函數只是輸出參數的計算值,傳遞參數的方式是copy方式。
接著換成引用方式:
#include <iostream>
using namespace std;
void f(int &i)
{
cout<<i*i<<endl;
}
int main()
{
int a=11;
f(a);//121
return 0;
}
換成了引用,結果沒有什麼變化。
但是如果參數的類型是個復雜的類型,比如自定義對象。那麼引用可以節省不少在copy上所花的開銷。
然而出現一個新的問題:
由於引用持有原實參同樣的內存區,混參數副作用,我們的函數可能無意間修改了原對象,不僅危險而且出錯時排錯也比較困難,於是養成一個使用const的習慣,對於我們實現知道有些函數根本不應該修改實參時:
#include <iostream>
using namespace std;
void f(const int &i)
{
cout<<i*i<<endl;
}
int main()
{
int a=11;
f(a);//121
return 0;
}
於是
如果
void f(const int &i)
{
i=12;//error
cout<<i*i<<endl;
}
會報錯的。
其實函數的返回值也可以用const限制的,什麼,這個還需要嗎?
看看下面的代碼:
#include <iostream>
using namespace std;
int f(int &i)
{
i=12;
return i;
}
int main()
{
int a=11;
cout<<f(a);//12
return 0;
}
沒有什麼特殊之處吧,接著改改:
#include <iostream>
using namespace std;
int& f(int &i)
{
i=12;
return i;
}
int main()
{
int a=11;
cout<<f(a);//12
return 0;
}
返回引用,結果沒什麼變化吧。
但是現在f(a)返回了a的引用,可能會有被修改的危險!!!
#include <iostream>
using namespace std;
int& f(int &i)
{
i=12;
return i;
}
int main()
{
int a=11;
f(a)=33;
cout<<a;//33
return 0;
}
這裡f(a)可以做左值,有時候我們並不希望這樣的事情發生,於是const發揮了:
#include <iostream>
using namespace std;
const int& f(int &i)
{
i=12;
return i;
}
int main()
{
int a=11;
f(a)=33;//error
return 0;
}
7.const對象和const 成員函數
#include <iostream>
using namespace std;
class Test
{
private:
int i;
public:
Test(int ii){i=ii;};
void setVal(int i){this->i=i;}
void echoVal(){cout<<i<<endl;}
};
int main()
{
Test a(123);
a.setVal(456);
a.echoVal();//456
return 0;
}
沒有什麼特殊之處吧.
但是如果我們想要const Test a(123);這樣的常量對象,他的成員不允許修改,編譯器可以實現這些,只需標識其成員只讀即可。
然而怎麼知道哪些函數可以安全調用呢,默認可能他認為所有方法對自己不利,不能調用,可是我們如果想調用一些方法(這些方法實際並不會帶來什麼危險)怎麼辦呢,於是需要和其他方法區別開來,於是有了const成員函數,
const對象只能調用const成員函數(構造析構函數除外):
#include <iostream>
using namespace std;
class Test
{
private:
int i;
public:
Test(int ii){i=ii;};
void setVal(int ii){i=ii;}
void echoVal()const{cout<<i<<endl;}
};
int main()
{
const Test a(123);
a.echoVal();//123
return 0;
}