C++成员解除引用运算符详解:数据与函数指针的正确用法
在 C++ 中,成员解除引用运算符提供了一种灵活的操作类内部结构的方式。它允许程序在运行时动态选择要访问的成员变量或调用的成员函数,而非在编译期硬编码。掌握这一特性对于编写通用的容器管理或策略模式代码至关重要。
结果与目标
使用 C++ 的成员指针,可以在不改变类定义的情况下,让同一套逻辑操作不同的数据成员(如 feet 与 inches)或执行不同的行为(如 show_in() 与 show_ft())。这将提升代码的复用性与可配置性。
准备条件
- 理解对象内存模型:类的成员变量是特定对象的一部分,但“指向成员的指针”并不直接指向具体的内存地址,而是指向该类结构中该成员的偏移量位置。
- 基础语法知识:熟悉
&(取地址)、.(成员访问)、->(指针解引用)以及*(解引用运算符)。 - 开发环境:支持 C++98 及以上标准的编译器(如 GCC, Clang, MSVC)。
真实操作顺序
第1步:定义包含多个同类型成员的结构体
为了演示成员指针的灵活性,首先定义一个包含两个整型成员变量的类。这里以测量单位为例,定义英尺 (feet) 和英寸 (inches)。
class Example
{
private:
int feet;
int inches;
public:
Example();
Example(int ft);
~Example();
void show_in()const; // 显示英寸
void show_ft()const; // 显示英尺
void use_ptr()const; // 演示指针用法
};
此时,若没有创建对象,inches 仅是一个符号标识符。只有创建了对象(如 Example ob;),该成员才拥有实际的内存空间。
第2步:声明并初始化指向数据成员的指针
声明指向成员的指针需使用 类名::成员名 格式,并赋值时加上取地址符 &。注意,此处的 Example::* 表示这是一个属于 Example 类的成员指针。
// pt 是指向 Example 类中 int 类型成员的指针
int Example::*pt = &Example::inches;
此时 pt 本身不包含任何对象的值,它仅仅记录了 “inches 在这个类里的位置”。
第3步:使用成员解除引用运算符访问数据
要实际获取数据,必须将成员指针与具体的对象实例结合。核心规则如下:
obj.*ptr:当对象是实体时使用点号(.)。ptr_obj->*ptr:当对象是通过指针访问时使用箭头(->)。
Example ob1; Example ob2; Example *pq = new Example; // 访问 ob1 对象中由 pt 指向的成员(当前为 inches) cout << ob1.*pt << endl; // 访问 pq 所指向对象中由 pt 指向的成员 cout << pq->*pt << endl;
如果希望操作同一个对象的其他成员,只需重新赋值 pt:
pt = &Example::feet; // 现在 pt 指向 feet 成员
// ob1.*pt 将返回 feet 的值,而非 inches
第4步:声明指向成员函数的指针
指向成员函数的指针比普通函数指针复杂,必须包含返回值类型、参数列表以及所属类。由于普通函数指针不需要指定所属类(通常默认为全局),成员函数指针必须在括号内标明类域。
// 声明指向 返回void、无参、const 修饰的成员函数的指针
void (Example::*pf)()const;
第5步:调用成员函数
赋值后,可以通过对象调用该函数。关键点在于:调用表达式必须被括号包围,否则编译器可能会错误解析优先级。
// 关联具体的方法
pf = &Example::show_in;
Example ob3(20);
// 正确写法:先进行成员解引用得到函数名,再进行调用
(ob3.*pf)();
由于 show_in() 和 show_ft() 签名完全一致,我们可以随时切换 pf 的行为:
pf = &Example::show_feet;
(ob3.*pf)(); // 现在输出的是 feet 的内容
完成判断
当程序运行 car.use_ptr() 或 van.use_ptr() 时,观察控制台输出的变化。如果在 use_ptr 内部动态更改了 pt 或 pf 的值,且 cout 输出的数值确实对应了修改后的字段或执行了预期的打印函数,即说明成员解除引用机制工作正常。完整的逻辑验证可以参考下方的综合示例。
综合示例代码
以下代码展示了如何在类内部方法中使用成员指针操作自身 this 以及其他外部对象 yard。
#include <iostream>
using namespace std;
class Example {
private:
int feet;
int inches;
public:
Example() : feet(0), inches(0) {}
Example(int ft) : feet(ft), inches(12*ft) {}
~Example() {}
void show_in() const { cout << inches << " inches\n"; }
void show_ft() const { cout << feet << " feet\n"; }
void use_ptr() const {
Example yard(3); // 局部对象
// --- 测试数据成员指针 ---
int Example::*pt;
pt = &Example::inches;
cout << "Set pt to &Example::inches:\n";
// 使用 this 指针访问调用者的成员
cout << "this->*pt: " << this->*pt << endl;
// 使用局部对象访问其成员
cout << "yard.*pt: " << yard.*pt << endl;
pt = &Example::feet;
cout << "Set pt to &Example::feet:\n";
cout << "this->*pt: " << this->*pt << endl;
cout << "yard.*pt: " << yard.*pt << endl;
// --- 测试成员函数指针 ---
void (Example::*pf)()const;
pf = &Example::show_in;
cout << "Set pf to &Example::show_in:\n";
// 注意括号必不可少
cout << "Using (this->*pf)(): ";
(this->*pf)();
cout << "Using (yard.*pf)(): ";
(yard.*pf)();
}
};
int main()
{
Example car(15);
Example van(20);
cout << "car.use_ptr() output:\n";
car.use_ptr();
cout << "\nvan.use_ptr() output:\n";
van.use_ptr();
return 0;
}
排错提示
- 优先级混淆:最常见的错误是忘记给函数调用加括号,写成
*ob3.pf而不是(ob3.*pf)()。前者会先解引用指针再访问成员,导致语义错误。 - 类型不匹配:指向成员变量的指针必须确保源和目标类型一致(如
int对int),指向函数的指针必须确保参数列表、返回值及const属性完全一致。 - 丢失
&符号:给成员指针赋值时,必须使用&ClassName::MemberName,直接写ClassName::MemberName会报错。
简要总结
C++ 的成员解除引用运算符(.* 和 ->*)是实现细粒度控制的核心工具。通过分离“位置的定位”(成员指针声明)与“目标的访问”(对象实例操作),程序员可以构建出高度抽象的数据处理逻辑。无论是遍历不同属性的数组,还是在运行时决定算法执行路径,这都是一项不可或缺的技术。以上就是C++成员解除引用运算符的详细内容,更多关于C++高级指针技巧的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









