C++数据成员指针
classData1{public:inta;charb;};int Data1:: * aa = &Data1::a;
这行代码定义了一个指向Data1类中int类型成员变量的指针aa,并将其初始化为指向成员a。
int Data1::*是指向Data1类中int类型数据成员的指针类型。aa是指针变量的名字。&Data1::a获取类成员a的“地址”(实际上是成员相对于对象起始位置的偏移量,而不是内存中的绝对地址)。
之后可以通过Data1的对象或指针来访问该成员:
Data1 obj;obj.*aa=42;// 等价于 obj.a = 42;Data1*p=&obj;p->*aa=100;// 等价于 p->a = 100;拓展
详细解析指向数据成员的指针(Pointer to Data Member)的语法。以给出的代码为例:
intData1::*aa=&Data1::a;1. 类型声明的语法拆解
intData1::*aa;int:成员变量的类型(a是int类型)。Data1::*:这是核心语法,表示“指向Data1类的成员”的指针。
其中::*是一个整体运算符,称为成员指针声明符。aa:变量名,即这个成员指针的名字。
可以类比普通指针:
int* p;中的*表示“指向 int 的指针”;
这里的Data1::*表示“指向Data1中某个成员的指针”,而前面的int指明该成员的类型。
更完整的类型描述是:指向Data1类中int类型的数据成员的指针。
2. 初始化的语法
aa=&Data1::a;&Data1::a不是取普通变量的地址,而是取类成员 a的“偏移地址”。
它返回一个“成员指针”值,这个值本质上是a在Data1对象中的字节偏移量(或编译器内部标识)。- 注意:不能写成
&a,因为a不属于任何具体对象,它是类的一个成员,必须通过类名::成员名来取。
语法要点:&类名::成员名产生一个指向该成员的指针。
3. 为什么需要这种指针?
普通指针指向某个具体对象的某个成员(如int* p = &obj.a;)。
而数据成员指针指向的是成员在类中的“位置”,并不绑定到某个具体对象。
它可以在不同对象上使用,实现“延迟绑定成员访问”。
4. 如何使用(解引用)
成员指针不能直接解引用,必须结合一个具体的对象或对象指针,使用两个特殊的运算符:
.*(点星运算符):用于对象->*(箭头星运算符):用于对象指针
示例:
Data1 obj;obj.a=10;// 通过成员指针访问obj.*aa=20;// 等价于 obj.a = 20;Data1*p=&obj;p->*aa=30;// 等价于 p->a = 30;注意:
.*和->*是 C++ 中优先级较低的运算符,通常需要加括号,但赋值时优先结合规则尚可。
5. 底层概念(简化理解)
- 成员指针的值通常不是真正的内存地址,而是偏移量(字节数)。
比如如果Data1定义为:
那么classData1{intx;// 偏移 0inta;// 偏移 4(假设 int 4 字节)};&Data1::a的值在底层可能是4。 - 执行
obj.*aa时,编译器将obj的起始地址加上偏移量4,从而访问到obj.a。
这种实现方式意味着:
- 成员指针不能指向静态成员(静态成员不属于对象,没有偏移量)。
- 成员指针之间可以比较相等性(如果指向同一个成员)。
- 成员指针可以用于虚基类的情况,但偏移量计算会复杂。
6. 类型别名简化
复杂的类型声明可以用using或typedef简化:
usingIntMemberOfData1=intData1::*;IntMemberOfData1 aa=&Data1::a;7. 常见应用场景
- 遍历对象的多个同类型成员:例如一个结构体有多个
int字段,可以通过成员指针数组批量操作。 - 实现数据绑定或属性系统:将成员指针与对象结合,延迟具体成员的访问。
- 编写泛型代码:模板中可以使用
T Class::*来表示任意类型的成员指针。
8. 与普通指针的区别总结
| 特性 | 普通指针int* | 数据成员指针int Data1::* |
|---|---|---|
| 指向的目标 | 某个具体对象的成员 | 类的某个成员的位置(偏移) |
| 初始化 | &obj.a或nullptr | &Data1::a或nullptr |
| 解引用需要结合对象 | 直接*p | obj.*mp或ptr->*mp |
| 占用大小 | 通常 4 或 8 字节(地址) | 通常 4 或 8 字节(偏移量) |
| 指针运算(+/-) | 支持 | 不支持(偏移量不能算术运算) |
| 可以指向静态成员吗 | 可以(&Data1::s_a) | 不可以 |
9. 完整可运行示例
#include<iostream>usingnamespacestd;classData1{public:inta;intb;Data1(intx,inty):a(x),b(y){}};intmain(){intData1::*p=&Data1::a;// 指向 aintData1::*q=&Data1::b;// 指向 bData1obj(10,20);cout<<obj.*p<<endl;// 输出 10cout<<obj.*q<<endl;// 输出 20obj.*p=100;cout<<obj.a<<endl;// 输出 100return0;}