指向成员的指针
指向成员的指针的声明是指针声明的特例。使用以下序列来声明它们:
1
2
3
|
[storage- class -specifiers] [cv-qualifiers] type-specifiers [ms-modifier] qualified-name ::* [cv-qualifiers] identifier [= & qualified-name :: member-name]; |
声明说明符:
- 可选存储类说明符。
- 可选 const 和/或 volatile 说明符。
- 类型说明符:类型的名称。这是要指向的成员的类型,而不是类。
声明符:
- 可选的 Microsoft 专用修饰符。
- 包含要指向的成员的类的限定名。
- :: 运算符。
- * 运算符。
- 可选 const 和/或 volatile 说明符。
- 命名指向成员的指针的标识符。
可选的初始值设定项:
- = 运算符。
- & 运算符。
- 类的限定名。
- :: 运算符。
- 适当类型的类的非静态成员的名称。
像往常一样,允许在单个声明中使用多个声明符(以及任何关联的初始值设定项)。
指向类的成员的指针与普通指针不同,因为它有该成员的类型的类型信息和该成员所属的类的类型信息。常规指针只标识内存中的一个对象或只具有其地址。指向类的某个成员的指针标识类的所有实例中的该成员。以下示例声明类、Window 和一些指向成员数据的指针。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// 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 成员函数。
1
2
|
const char * (Window::*pfnwGC)() = &Window::GetCaption; bool (Window::*pfnwSC)( const char * ) = &Window::SetCaption; |
指针 pfnwGC 和 pfnwSC 分别指向 GetCaption 类的 SetCaption 和 Window。以下代码直接使用指向成员 pwCaption 的指针将信息复制到窗口标题:
1
2
3
4
5
6
7
8
9
10
|
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'; |
.* 和 –>* 运算符(指向成员的指针运算符)的区别在于 .* 运算符选择成员给定的对象或对象引用,而 –>* 运算符通过指针选择成员。(有关这些运算符的更多信息,请参阅使用指向成员的指针运算符的表达式。)
指向成员的指针运算符的结果是成员的类型 - 本例中为 char *。
以下代码片段使用指向成员的指针调用成员函数 GetCaption 和 SetCaption:
1
2
3
4
5
6
7
8
9
10
11
12
|
// 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 ); |
针对指向成员的指针的限制
静态成员的地址不是指向成员的指针。它是指向静态成员的一个实例的常规指针。由于给定类的所有对象只存在一个静态成员实例,因此可以使用普通的 address-of (&) 和取消引用 (*) 运算符。
指向成员和虚函数的指针
通过指向成员函数的指针调用虚函数就如同直接调用函数一样;将在 v 表中查找并调用正确的函数。
一直以来,虚函数工作的关键是通过指向基类的指针来调用它们。(有关虚函数的详细信息,请参阅虚函数。)
以下代码演示如何通过指向成员函数的指针调用虚函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
// 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 类型的非静态成员函数中访问的指针。它指向为其调用成员函数的对象。静态成员函数没有 this 指针。
语法
1
2
|
this this ->member-identifier |
备注
对象的 this 指针不是对象的一部分;它没有在对象上的 sizeof 语句的结果中反映。相反,当对某个对象调用非静态成员函数时,该对象的地址将由编译器作为隐藏的参数传递给函数。例如,以下函数调用:
1
|
myDate.setMonth( 3 ); |
可以按以下方式解释:
1
|
setMonth( &myDate, 3 ); |
对象的地址可从成员函数的内部作为 this 指针提供。 this 的大多数使用都是隐式的。在引用类的成员时显式使用 this 是合法的,但没有必要。例如:
1
2
3
4
5
6
|
void Date::setMonth( int mn ) { month = mn; // These three statements this ->month = mn; // are equivalent (* this ).month = mn; } |
表达式 *this 通常用于从成员函数返回当前对象:
1
|
return * this ; |
this 指针还用于防止自引用:
1
2
|
if (&Object != this ) { // do not execute in cases of self-reference |
注意
由于 this 指针无法更改,因此不允许对 this 赋值。C++ 的早期实现允许对 this 赋值。
this 指针有时可直接使用 - 例如,当操作自引用数据结构,而其中需要当前对象的地址时。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
// 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(); } |
输出:
1
2
|
my buffer your buffer |
this 指针的类型
通过 const 和 关键字,可以在函数声明中修改 volatilethis 指针的类型。若要将函数声明为具有一个或多个关键字的特性,请将关键字添加到函数参数列表的后面。
请看以下示例:
1
2
3
4
5
6
7
8
|
// 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 指针:
1
2
3
4
5
6
7
8
|
// type_of_this_pointer2.cpp class Point { unsigned X() const ; }; int main() { } |
成员函数中 this 指针的类型由以下语法描述,其中,cv-qualifier-list 是从成员函数声明符中确定的,可以是 const 和/或 volatile,而 class-type 是类的名称:
1
|
[cv-qualifier-list] class -type * const this |
换言之,this 始终是 const 指针;无法重新指派它。成员函数声明中使用的 const 或 volatile 限定符适用于由该函数范围中的 this 指向的类实例。
下表介绍了有关这些修饰符的工作方式的更多信息。
this 修饰符的语义
修饰符 |
|
---|---|
const | 不能更改数据成员;无法调用不是 const 的成员函数。 |
volatile | 每次访问成员数据时,都会从内存中加载该数据;禁用某些优化。 |
将 const 对象传递给不是 const 的成员函数是错误的。同样,将 volatile 对象传递给不是 volatile 的成员函数也是错误的。
声明为 const 的成员函数不能更改数据成员 - 在此类函数中,this 指针是指向 const 对象的指针。
注意
构造函数和析构函数不能声明为 const 或 volatile。但是,可以在 const 或 volatile 对象上调用它们。