const修飾類的成員函數
const修飾變量一般有兩種方式:const T *a,或者 T const *a,這兩者都是一樣的,主要看const位于*的左邊還是右邊,這裡不再贅述,主要來看一下當const修飾類的成員函數時,成員函數有什麼特點。
https://www.cnblogs.com/cthon/p/9166715.html
類的成員函數後面加 const,表明這個函數不會對這個類對象的資料成員(準确地說是非靜态資料成員)作任何改變。
在設計類的時候,一個原則就是對于不改變資料成員的成員函數都要在後面加 const,而對于改變資料成員的成員函數不能加 const。是以 const 關鍵字對成員函數的行為作了更加明确的限定:
(1)有 const 修飾的成員函數(指 const 放在函數參數表的後面,而不是在函數前面或者參數表内),隻能讀取資料成員,不能改變資料成員;沒有 const 修飾的成員函數,對資料成員則是可讀可寫的。
(2)除此之外,在類的成員函數後面加 const 還有什麼好處呢?那就是常量(即 const)對象可以調用 const 成員函數,而不能調用非const修飾的函數。
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class A
{
public:
void f()
{
cout<<"non const"<<endl;
}
void f() const
{
cout<<" const"<<endl;
}
};
int main(int argc, char **argv)
{
A a;
a.f();
const A &b=a;
b.f();
const A *c=&a;
c->f();
A *const d=&a;
d->f();
A *const e=d;
e->f();
const A *f=c;
f->f();
return 0;
}
注意:兩個成員函數如果隻是常量性不同,是可以被重載的。看下面解釋的第二點:
C++的const類型成員函數(解釋為什麼非const成員函數不能通路const類對象的資料成員)
1. 在C++中隻有被聲明為const的成員函數才能被一個const類對象調用。
在C++中,隻有被聲明為const的成員函數才能被一個const類對象調用。
如果要聲明一個const類型的類成員函數,隻需要在成員函數清單後加上關鍵字const, 例如:
class Screen {
public:
char get() const;
};
在類體之外定義const成員函數時,還必須加上const關鍵字,例如:
char Screen :: get() const {
return _screen[_cursor];
}
若将成員函數聲明為const,則不允許通過其修改類的資料成員。 值得注意的是,如果類中存在指針類型的資料成員即便是const函數隻能保證不修改該指針的值,并不能保證不修改指針指向的對象。例如:
class Name {
public:
void setName(const string &s) const;
private:
char *m_sName;
};
void setName(const string &s) const {
m_sName = s.c_str(); // 錯誤!不能修改m_sName;
for (int i = 0; i < s.size(); ++i)
m_sName[i] = s[i]; // 不好的風格,但不是錯誤的
}
2. const成員函數可以被對應的具有相同形參清單的非const成員函數重載,例如:
class Screen {
public:
char get(int x,int y);
char get(int x,int y) const;
};
int main()
{
const Screen cs;
Screen cc2;
char ch = cs.get(0, 0); // 調用const成員函數
ch = cs2.get(0, 0); // 調用非const成員函數
}
在這種情況下,類對象的常量性決定調用哪一個函數:
- const成員函數可以通路非const對象的非const資料成員,const資料成員,也可以通路const對象内的所有資料成員;
- 非const成員函數隻可以通路非const對象的任意的資料成員(不能通路const對象的任意資料成員);(上述原因可詳見C++Primer(5th)231頁。 在預設情況下,this的類型是指向類類型非常量版本的常量指針,例如 Screen類中,this類型為 Screen *cosnt。當在成員函數的後面加上const關鍵字時,隐式的将this指針修改為 const Screen *const 即指向類類型常量版本的常量指針。根據初始化原則,我們不能将一個常量指針指派給一個非常量指針)
- 作為一種良好的程式設計風格,在聲明一個成員函數時,若該成員函數并不對資料成員進行修改, 應盡可能将該成員函數聲明為const成員函數。
2. const修飾的是誰?
const成員函數的寫法有兩種
1、void fun(int a,int b) const{}
2、void const fun(int a,int b){}
這兩種寫法的本質是:void fun (const 類 *this, int a,int b);
const修飾的不是形參a和b;const修飾的是屬性this->a和this->b。與const所寫的位置無關。
為什麼?
因為c++對類的this指針做了隐藏,本質上,const指針修飾的是被隐藏的this指針所指向的記憶體空間,修飾的是this指針。
總結:
1)const成員函數可以通路非const對象的非const資料成員、const資料成員,也可以通路const對象内的所有資料成員;
2)非const成員函數可以通路非const對象的非const資料成員、const資料成員,但不可以通路const對象的任意資料成員;
3)作為一種良好的程式設計風格,在聲明一個成員函數時,若該成員函數并不對資料成員進行修改操作,應盡可能将該成員函數聲明為const 成員函數。
4)如果隻有const成員函數,非const對象是可以調用const成員函數的。當const版本和非const版本的成員函數同時出現時,非const對象調用非const成員函數。
補充:
> 類中的const成員變量都要放在初始化清單之中進行
> const資料成員
> 引用資料成員
> 對象資料成員(内置類)
const成員函數
> void print() const => const 類名 * const this
> 在其内部是不能修改資料成員
> 隻能調用const成員函數,不能調用非const成員函數
> const對象隻能調用const成員函數,必須要提供一個const版本的成員函數
const成員函數和成員變量這一塊的邏輯容易混亂!