指向成员的指针
指向成员的指针的声明是指针声明的特例。使用以下序列来声明它们:
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 对象上调用它们。