C++ const常量成員函數
const的的用法太多了,常量成員函數就是曾經讓我迷惑的用法之一,即在成員函數的參數清單之後加上const。
this 指針
在說常量成員函數之前,必須得詳細知道this指針,以前我們知道不論C++還是java中,this都可以表示對象本身,事實如此,而在C++中更準确的定義是:
this是一個額外的隐式參數,用來通路目前對象,而它的本質是一個常量指針
常量指針(const pointer),差別于指向常量的指針(const to pointer),前者表示指針的值不能被修改(位址不變),後者表示指針所綁定的對象的值不能被修改,由于this就指向目前對象,我們不能用this在去綁定其他對象,是以他就是一個常量指針。
假設現在有一個類
class people
則this的類型是:
people *const
const成員函數
那麼現在問題來了,const成員函數究竟是什麼玩意?
上面提到,this指針是一個非常量版本的常量指針,那麼當我們建立常量對象的時候,不能把this綁定到一個常量對象上——即不能使用一個常量對象調用普通函數。
代碼:
class people{
public:
people(){}
people(int x) :score(x){}
~people(){}
int getScore(){ return score; }
private:
int score;
};
int main()
{
const people p1();
cout << p1.getScore() << endl;//error
system("pause");
return ;
}
這段代碼編譯器直接報錯:
對象包含于成員函數不相容類型的限定符。
這也就說明了普通指針(包括非常量指針和常量指針)無法綁定一個常量對象。簡單來講,下述語句無法成立:
const double pi=;
double* ptr1=π//error1
double* const ptr2=π//error2
const double* ptr1=π//ok1
const double* const ptr2=π//ok2
我們需要用一個指向常量的指針來綁定常量對象。
那麼現在問題又來了,怎麼使隐式調用的this指針變成指向常量的常量指針?
答案就是在成員函數的參數清單後面加入關鍵字const,例如上述示例中:
int getScore() const { return score; }
這樣我們就可以使用常量對象調用
getScore()
方法了
class people{
public:
//...
int getScore() const{ return score; }
//...
};
int main()
{
const people p1();
cout << p1.getScore() << endl;//ok
system("pause");
return ;
}
這樣就叫做常量成員函數(const member function),我們可以使用非常量對象調用常量成員函數,這樣做是合法的,因為我們可以使用指向常量的指針來綁定一個非常量對象,例如,下述語句合法:
double pi = ;
const double * ptr=π
是以,下述使用也是合法:
class people{
public:
//...
int getScore() const{ return score; }
//...
};
int main()
{
people p2();
cout << p2.getScore() << endl;//ok
//...
}
—————–2016年5月29号更新—————–
關于const成員函數的補充
對于一個成員函數來說,它有一個隐藏的參數,來表示對象的位址,例如:
class Foo
{
public:
void hello(int a)
{
cout << "hello"+a<<endl;
}
};
//...
int main()
{
Foo foo;
int a=;
foo.hello(a);
//等價于
foo.hello(&foo,a);
}
從上述代碼看出,這裡相當于有一個該對象位址的隐式參數傳遞,也就是說,從函數聲明的角度,這裡應該是這個樣子:
class Foo
{
public:
void hello(Foo* this ,int a)
{
cout << "hello"+a<<endl;
}
};
當我們給成員函數的聲明後面加上const以後,例如:
void hello(int a) const
{
cout << "hello"+a<<endl;
}
這裡就可以了解為有一個const的指針作為參數,如
void hello(const Foo * this,int a) const
{
cout << "hello"+a<<endl;
}
因為this是const的類型的,當然也就防止了成員函數對類中成員進行修改。
知道了這個東西,就能正确引導我們的使用。
比如說,假如有一個class
class A
{
//...
public:
void func1() const;
void func2();
}
我們在使用的時候可能有如下組合:
int main()
{
//...
A a1;
const a2;
a1.func1();
//等價于a1.func1(&a1);//ok
a1.func2();
//等價于a1.func2(&a1);//ok
a2.func1();
//等價于a2.func1(&a2);//ok
a2.func2();
//等價于a2.func2(&a2);//error
}
情況1,用const的指針綁定普通對象,可行,類似于:
int a =;
const int *pa=&a;
情況2,用普通指針綁定普通對象,可行,類似于:
int a=;
int *pa=&a;
情況3,用const指針綁定常量對象,可行,類似于:
const int a =;
const int *pa=&a;
情況4,用普通指針綁定const對象,不可行,類似于:
const int a =;
int *pa= &a;//error
參考:http://stackoverflow.com/questions/3141087/what-is-meant-with-const-at-end-of-function-declaration