C++編程指向成員的指針以及this指針的基本使用指南
指向成員的指針
指向成員的指針的聲明是指針聲明的特例。使用以下序列來聲明它們:
[storage-class-specifiers] [cv-qualifiers] type-specifiers [ms-modifier] qualified-name ::* [cv-qualifiers] identifier [= & qualified-name :: member-name];
聲明說明符:
- 可選存儲類說明符。
- 可選 const 和/或 volatile 說明符。
- 類型說明符:類型的名稱。這是要指向的成員的類型,而不是類。
聲明符:
- 可選的 Microsoft 專用修飾符。
- 包含要指向的成員的類的限定名。
- :: 運算符。
- * 運算符。
- 可選 const 和/或 volatile 說明符。
- 命名指向成員的指針的標識符。
可選的初始值設定項:
- = 運算符。
- & 運算符。
- 類的限定名。
- :: 運算符。
- 適當類型的類的非靜態(tài)成員的名稱。
像往常一樣,允許在單個聲明中使用多個聲明符(以及任何關聯(lián)的初始值設定項)。
指向類的成員的指針與普通指針不同,因為它有該成員的類型的類型信息和該成員所屬的類的類型信息。常規(guī)指針只標識內存中的一個對象或只具有其地址。指向類的某個成員的指針標識類的所有實例中的該成員。以下示例聲明類、Window 和一些指向成員數據的指針。
// pointers_to_members1.cpp class Window { public: Window(); // Default constructor. Window( int x1, int y1, // Constructor specifying int x2, int y2 ); // window size. bool SetCaption( const char *szTitle ); // Set window caption. const char *GetCaption(); // Get window caption. char *szWinCaption; // Window caption. }; // Declare a pointer to the data member szWinCaption. char * Window::* pwCaption = &Window::szWinCaption; int main() { }
在前面的示例中,pwCaption 是一個指針,它指向具有 Windowchar* 類型的類 的任何成員。類型 pwCaption 不是 char * Window::*。下一個代碼片段將指針聲明為 SetCaption 和 GetCaption 成員函數。
const char * (Window::*pfnwGC)() = &Window::GetCaption; bool (Window::*pfnwSC)( const char * ) = &Window::SetCaption;
指針 pfnwGC 和 pfnwSC 分別指向 GetCaption 類的 SetCaption 和 Window。以下代碼直接使用指向成員 pwCaption 的指針將信息復制到窗口標題:
Window wMainWindow; Window *pwChildWindow = new Window; char *szUntitled = "Untitled - "; int cUntitledLen = strlen( szUntitled ); strcpy_s( wMainWindow.*pwCaption, cUntitledLen, szUntitled ); (wMainWindow.*pwCaption)[cUntitledLen - 1] = '1'; //same as //wMainWindow.SzWinCaption [cUntitledLen - 1] = '1'; strcpy_s( pwChildWindow->*pwCaption, cUntitledLen, szUntitled ); (pwChildWindow->*pwCaption)[cUntitledLen - 1] = '2'; //same as //pwChildWindow->szWinCaption[cUntitledLen - 1] = '2';
.* 和 –>* 運算符(指向成員的指針運算符)的區(qū)別在于 .* 運算符選擇成員給定的對象或對象引用,而 –>* 運算符通過指針選擇成員。(有關這些運算符的更多信息,請參閱使用指向成員的指針運算符的表達式。)
指向成員的指針運算符的結果是成員的類型 - 本例中為 char *。
以下代碼片段使用指向成員的指針調用成員函數 GetCaption 和 SetCaption:
// Allocate a buffer. enum { sizeOfBuffer = 100 }; char szCaptionBase[sizeOfBuffer]; // Copy the main window caption into the buffer // and append " [View 1]". strcpy_s( szCaptionBase, sizeOfBuffer, (wMainWindow.*pfnwGC)() ); strcat_s( szCaptionBase, sizeOfBuffer, " [View 1]" ); // Set the child window's caption. (pwChildWindow->*pfnwSC)( szCaptionBase );
針對指向成員的指針的限制
靜態(tài)成員的地址不是指向成員的指針。它是指向靜態(tài)成員的一個實例的常規(guī)指針。由于給定類的所有對象只存在一個靜態(tài)成員實例,因此可以使用普通的 address-of (&) 和取消引用 (*) 運算符。
指向成員和虛函數的指針
通過指向成員函數的指針調用虛函數就如同直接調用函數一樣;將在 v 表中查找并調用正確的函數。
一直以來,虛函數工作的關鍵是通過指向基類的指針來調用它們。(有關虛函數的詳細信息,請參閱虛函數。)
以下代碼演示如何通過指向成員函數的指針調用虛函數:
// virtual_functions.cpp // compile with: /EHsc #include <iostream> using namespace std; class Base { public: virtual void Print(); }; void (Base ::* bfnPrint)() = &Base :: Print; void Base :: Print() { cout << "Print function for class Base\n"; } class Derived : public Base { public: void Print(); // Print is still a virtual function. }; void Derived :: Print() { cout << "Print function for class Derived\n"; } int main() { Base *bPtr; Base bObject; Derived dObject; bPtr = &bObject; // Set pointer to address of bObject. (bPtr->*bfnPrint)(); bPtr = &dObject; // Set pointer to address of dObject. (bPtr->*bfnPrint)(); } //Output: Print function for class Base Print function for class Derived
this 指針
this 指針是只能在 class、struct或 union 類型的非靜態(tài)成員函數中訪問的指針。它指向為其調用成員函數的對象。靜態(tài)成員函數沒有 this 指針。
語法
this this->member-identifier
備注
對象的 this 指針不是對象的一部分;它沒有在對象上的 sizeof 語句的結果中反映。相反,當對某個對象調用非靜態(tài)成員函數時,該對象的地址將由編譯器作為隱藏的參數傳遞給函數。例如,以下函數調用:
myDate.setMonth( 3 );
可以按以下方式解釋:
setMonth( &myDate, 3 );
對象的地址可從成員函數的內部作為 this 指針提供。 this 的大多數使用都是隱式的。在引用類的成員時顯式使用 this 是合法的,但沒有必要。例如:
void Date::setMonth( int mn ) { month = mn; // These three statements this->month = mn; // are equivalent (*this).month = mn; }
表達式 *this 通常用于從成員函數返回當前對象:
return *this;
this 指針還用于防止自引用:
if (&Object != this) { // do not execute in cases of self-reference
注意
由于 this 指針無法更改,因此不允許對 this 賦值。C++ 的早期實現允許對 this 賦值。
this 指針有時可直接使用 - 例如,當操作自引用數據結構,而其中需要當前對象的地址時。
// this_pointer.cpp // compile with: /EHsc #include <iostream> #include <string.h> using namespace std; class Buf { public: Buf( char* szBuffer, size_t sizeOfBuffer ); Buf& operator=( const Buf & ); void Display() { cout << buffer << endl; } private: char* buffer; size_t sizeOfBuffer; }; Buf::Buf( char* szBuffer, size_t sizeOfBuffer ) { sizeOfBuffer++; // account for a NULL terminator buffer = new char[ sizeOfBuffer ]; if (buffer) { strcpy_s( buffer, sizeOfBuffer, szBuffer ); sizeOfBuffer = sizeOfBuffer; } } Buf& Buf::operator=( const Buf &otherbuf ) { if( &otherbuf != this ) { if (buffer) delete [] buffer; sizeOfBuffer = strlen( otherbuf.buffer ) + 1; buffer = new char[sizeOfBuffer]; strcpy_s( buffer, sizeOfBuffer, otherbuf.buffer ); } return *this; } int main() { Buf myBuf( "my buffer", 10 ); Buf yourBuf( "your buffer", 12 ); // Display 'my buffer' myBuf.Display(); // assignment opperator myBuf = yourBuf; // Display 'your buffer' myBuf.Display(); }
輸出:
my buffer your buffer
this 指針的類型
通過 const 和 關鍵字,可以在函數聲明中修改 volatilethis 指針的類型。若要將函數聲明為具有一個或多個關鍵字的特性,請將關鍵字添加到函數參數列表的后面。
請看以下示例:
// type_of_this_pointer1.cpp class Point { unsigned X() const; }; int main() { }
上面的代碼聲明一個成員函數 X,其中,this 指針被視為指向 const 對象的 const 指針??梢允褂?cv-mod-list 選項的組合,但它們始終通過 this 修改指向的對象,而不是 this 指針本身。因此,以下聲明將聲明函數 X;this 指針是指向 const 對象的 const 指針:
// type_of_this_pointer2.cpp class Point { unsigned X() const; }; int main() { }
成員函數中 this 指針的類型由以下語法描述,其中,cv-qualifier-list 是從成員函數聲明符中確定的,可以是 const 和/或 volatile,而 class-type 是類的名稱:
[cv-qualifier-list] class-type * const this
換言之,this 始終是 const 指針;無法重新指派它。成員函數聲明中使用的 const 或 volatile 限定符適用于由該函數范圍中的 this 指向的類實例。
下表介紹了有關這些修飾符的工作方式的更多信息。
this 修飾符的語義
修飾符 | |
---|---|
const | 不能更改數據成員;無法調用不是 const 的成員函數。 |
volatile | 每次訪問成員數據時,都會從內存中加載該數據;禁用某些優(yōu)化。 |
將 const 對象傳遞給不是 const 的成員函數是錯誤的。同樣,將 volatile 對象傳遞給不是 volatile 的成員函數也是錯誤的。
聲明為 const 的成員函數不能更改數據成員 - 在此類函數中,this 指針是指向 const 對象的指針。
注意
構造函數和析構函數不能聲明為 const 或 volatile。但是,可以在 const 或 volatile 對象上調用它們。