C++ this指針詳解
this 是C++中的一個關鍵字,也是一個常量指針,指向當前對象(具體說是當前對象的首地址)。通過 this,可以訪問當前對象的成員變量和成員函數。
所謂當前對象,就是正在使用的對象,例如對于stu.say();,stu 就是當前對象,系統正在訪問 stu 的成員函數 say()。
假設 this 指向 stu 對象,那么下面的語句中,this 就和 pStu 的值相同:
Student stu; //通過Student類來創建對象Student *pStu = &stu;
[示例] 通過 this 來訪問成員變量:
class Student{private: char *name; int age; float score;public: void setname(char *); void setage(int); void setscore(float);};void Student::setname(char *name){ this->name = name;}void Student::setage(int age){ this->age = age;}void Student::setscore(float score){ this->score = score;}本例中,函數參數和成員變量重名是沒有問題的,因為通過 this 訪問的是成員變量,而沒有 this 的變量是函數內部的局部變量。例如對于this->name = name;語句,賦值號左邊是類的成員變量,右邊是 setname 函數的局部變量,也就是參數。
下面是一個完整的例子:
#include <iostream>using namespace std;class Student{private: char *name; int age; float score;public: void setname(char *); void setage(int); void setscore(float); void say();};void Student::setname(char *name){ this->name = name;}void Student::setage(int age){ this->age = age;}void Student::setscore(float score){ this->score = score;}void Student::say(){ cout<<this->name<<"的年齡是 "<<this->age<<",成績是 "<<this->score<<endl;}int main(){ Student stu1; stu1.setname("小明"); stu1.setage(15); stu1.setscore(90.5f); stu1.say(); Student stu2; stu2.setname("李磊"); stu2.setage(16); stu2.setscore(80); stu2.say(); return 0;}運行結果:
小明的年齡是 15,成績是 90.5李磊的年齡是 16,成績是 80
對象和普通變量類似;每個對象都占用若干字節的內存,用來保存成員變量的值,不同對象占用的內存互不重疊,所以操作對象A不會影響對象B。
上例中,創建對象 stu1 時,this 指針就指向了 stu1 所在內存的首字節,它的值和 &stu1 是相同的;創建對象 stu2 時,this 等于 &stu2;創建對象 stu3 時也一樣。
我們不妨來證明一下,給 Student 類添加一個成員函數,輸出 this 的值,如下所示:
void Student::printThis(){ cout<<this<<endl;}
然后在 main 函數中創建對象并調用 printThis:
Student stu1, *pStu1 = &stu1;stu1.printThis();cout<<pStu1<<endl;Student stu2, *pStu2 = &stu2;stu2.printThis();cout<<pStu2<<endl;
運行結果:
0x28ff300x28ff300x28ff100x28ff10
可以發現,this 確實指向了當前對象的首地址,而且對于不同的對象,this 的值也不一樣。
幾點注意:
this 是常量指針,它的值是不能被修改的,一切企圖修改該指針的操作,如賦值、遞增、遞減等都是不允許的。
this 只能在成員函數內部使用,其他地方沒有意義,也是非法的。
只有當對象被創建后 this 才有意義,因此不能在 static 成員函數中使用,后續會講到。
this 到底是什么
實際上,this 指針是作為函數的參數隱式傳遞的,它并不出現在參數列表中,調用成員函數時,系統自動獲取當前對象的地址,賦值給 this,完成參數的傳遞,無需用戶干預。
this 作為隱式參數,本質上是成員函數的局部變量,不占用對象的內存,只有在發生成員函數調用時才會給 this 賦值,函數調用結束后,this 被銷毀。
正因為 this 是參數,表示對象首地址,所以只能在函數內部使用,并且對象被實例化以后才有意義。
C++常對象及其成員
C++雖然采取了不少有效的措施(如設private保護)以增加數據的安全性,但是有些數據卻往往是共享的,人們可以在不同的場合通過不同的途徑訪問同一個數據對象。有時在無意之中的誤操作會改變有關數據的狀況,而這是人們所不希望出現的。
既要使數據能在一定范圍內共享,又要保證它不被任意修改,這時可以使用const,即把有關的數據定義為常量。
常對象
在定義對象時指定對象為常對象。常對象必須要有初值,如:
Time const t1(12,34,46); //t1是常對象
這樣,在所有的場合中,對象t1中的所有成員的值都不能被修改。凡希望保證數據成員不被改變的對象,可以聲明為常對象。
定義常對象的一般形式為:
類名 const 對象名[(實參表列)];
也可以把const寫在最左面:
const 類名 對象名[(實參表列)];
二者等價。
如果一個對象被聲明為常對象,則不能調用該對象的非const型的成員函數(除了由系統自動調用的隱式的構造函數和析構函數)。例如,對于例9.7中已定義的Time類,如果有
const Time t1(10,15,36); //定義常對象t1 t1.get_time( ); //企圖調用常對象t1中的非const型成員函數,非法
這是為了防止這些函數會修改常對象中數據成員的值。
不能僅依靠編程者的細心來保證程序不出錯,編譯系統充分考慮到可能出現的情況,對不安全的因素予以攔截。現在,編譯系統只檢查函數的聲明,只要發現調用了常對象的成員函數,而且該函數未被聲明為const,就報錯,提請編程者注意。
引用常對象中的數據成員很簡單,只需將該成員函數聲明為const即可。如:
void get_time( ) const ; //將函數聲明為const
這表示get_time是一個const型函數,即常成員函數。
常成員函數可以訪問常對象中的數據成員,但仍然不允許修改常對象中數據成員的值。有時在編程時有要求,一定要修改常對象中的某個數據成員的值,ANSI C++考慮到實際編程時的需要,對此作了特殊的處理,對該數據成員聲明為mutable,如:
mutable int count;
把count聲明為可變的數據成員,這樣就可以用聲明為const的成員函數來修改它的值。
常對象成員
可以將對象的成員聲明為const,包括常數據成員和常成員函數。
1) 常數據成員
其作用和用法與一般常變量相似,用關鍵字const來聲明常數據成員。常數據成員的值是不能改變的。
有一點要注意: 只能通過構造函數的參數初始化表對常數據成員進行初始化。如在類體中定義了常數據成員hour:
const int hour; //聲明hour為常數據成員
不能采用在構造函數中對常數據成員賦初值的方法,下面的做法是非法的:
Time::Time(int h){ hour=h; } // 非法
因為常數據成員是不能被賦值的。
在類外定義構造函數,應寫成以下形式:
Time::Time(int h):hour(h){} //通過參數初始化表對常數據成員hour初始化
常對象的數據成員都是常數據成員,因此常對象的構造函數只能用參數初始化表對常數據成員進行初始化。
2) 常成員函數
前面已提到,一般的成員函數可以引用本類中的非const數據成員,也可以修改它們。如果將成員函數聲明為常成員函數,則只能引用本類中的數據成員,而不能修改它們,例如只用于輸出數據等。如
void get_time( ) const ; //注意const的位置在函數名和括號之后
const是函數類型的一部分,在聲明函數和定義函數時都要有const關鍵字,在調用時不必加const。常成員函數可以引用const數據成員,也可以引用非const的數據成員。const數據成員可以被const成員函數引用,也可以被非const的成員函數引用。具體情況可以用下表表示。
那么怎樣利用常成員函數呢?
如果在一個類中,有些數據成員的值允許改變,另一些數據成員的值不允許改變,則可以將一部分數據成員聲明為const,以保證其值不被改變,可以用非const的成員函數引用這些數據成員的值,并修改非const數據成員的值。
如果要求所有的數據成員的值都不允許改變,則可以將所有的數據成員聲明為const,或將對象聲明為const(常對象),然后用const成員函數引用數據成員,這樣起到“雙保險”的作用,切實保證
如果已定義了一個常對象,只能調用其中的const成員函數,而不能調用非const成員函數(不論這些函數是否會修改對象中的數據)。這是為了保證數據的安全。如果需要訪問對象中的數據成員,可將常對象中所有成員函數都聲明為const成員函數,但應確保在函數中不修改對象中的數據成員。
不要誤認為常對象中的成員函數都是常成員函數。常對象只保證其數據成員是常數據成員,其值不被修改。如果在常對象中的成員函數未加const聲明,編譯系統把它作為非const成員函數處理。
還有一點要指出,常成員函數不能調用另一個非const成員函數。
新聞熱點
疑難解答
圖片精選