指向成员的指针(Pointer to Member)也称为成员指针,可能很多人对这一项技术比较陌生,也可能当你看到成员指针这个词会把它理解为类里面有个指针成员,实际上它们是两回事。成员指针是指通过指针来操作类里面的成员,包括两种——数据成员和函数成员。
我们知道访问外部全局数据和函数可以通过普通指针和函数指针来访问,例如:
int main() {
int a;
int *p = &a;
*p = 24;
int (*pfunc)(int, int) = my_max;
cout << pfunc(a, 25) << endl;
}
假如我们有这样一个类:
class Pairs {
public:
int a, b;
int max() {
return a > b ? a : b;
}
};
我们能不能也通过指针的方式来访问类里面的成员呢?这就要用到成员指针的语法了。用法如下:
void tpairs() {
// 定义一个对象
Pairs pair;
// 通过指向数据的成员指针给成员赋值
int Pairs::*pdata = &Pairs::a;
pair.*pdata = 12;
pdata = &Pairs::b;
pair.*pdata = 10;
// 通过指向成员函数的成员指针调用成员函数
int (Pairs::*pfunc)() = &Pairs::max;
cout << (pair.*pfunc)() << endl;
}
一般地,成员指针的定义语法如下:
// 指向数据成员的语法
type ClassName::*your_pointer_name = &ClassName::member;
// 指向成员函数的语法
type (ClassName::*your_pointer_name)(parameters list) [const] = &ClassName::method;
我们可以看到这里的语法设置的合理性,既然是类的,那就加个类解析符即可。使用成员指针有几点要注意:
1)成员指针的使用不能违背类的访问原则,即其只能访问类的公有成员部分;
2)当成员函数为 const 时,成员指针的定义后面也要加上const;
3)成员指针其本身相当于一个变量,需要存储空间(但有些特殊,后续会再探讨);
4)成员指针不能作算术运算(暂时的实验结果);
5)成员指针必须通过对象来访问,访问的运算符有 .* 和 ->*;
6)访问成员函数时,整体需要用括号括起来,即 (object.*pfunc)()或(object->*pfunc)();
7)当访问重载函数时,语法形式不变,编译器会帮我们自动选择。
所以当访问 const 成员函数时,我们要这样使用:
// 访问 const 成员函数
int (Pairs::*pfunc)() const = &Pairs::max;
cout << (pair.*pfunc)() << endl;
上面还提到 ->* 这个符号,它是当我们通过指针来访问对象时使用的,示例如下:
void tpairs() {
// 定义一个对象
Pairs *pair = new Pairs;
// 通过指向数据的成员指针给成员赋值
int Pairs::*pdata = &Pairs::a;
pair->*pdata = 12;
pdata = &Pairs::b;
pair->*pdata = 10;
// 通过指向成员函数的成员指针调用成员函数
// 访问 const 成员函数
int (Pairs::*pfunc)() const = &Pairs::max;
cout << (pair->*pfunc)() << endl;
delete pair;
}
访问重载函数的例子:
void tpairs() {
// 定义一个对象
Pairs *pair = new Pairs;
// 访问重载成员函数
int (Pairs::*pfunc)(int, int) const = &Pairs::max;
cout << (pair->*pfunc)(123, 321) << endl;
delete pair;
}
这篇文章先介绍到这里, 下一篇文章我将深入探讨成员指针的一些特性。