时间:2023-01-21 09:41:55 | 栏目:C代码 | 点击:次
C++的类成员指针是一种奇葩的指针。
假设现在我们要表示一个三维的点,现在有两种定义方式:
struct point1{ int x, y, z; }; struct point2{ int c[3]; };
第一种的优点是更直观,但第二种可以方便的用for遍历三个属性。最终我选择了第一种,但是我还想弄一个遍历功能怎么办?这个时候类成员指针就排上用场了,我们可以创建一个“指向point中具体成员的指针”。
int A:: *member = &A::x;
让member指针指向A中的成员x,且类型是int,此时我们就可以通过member来访问x:
point1 tmp{4, 5, 6}; cout << tmp.(*member); //把member解引用,得到tmp::x,表示要访问x
所以我们定义一个数组,就可以迭代访问类里的各种int属性了
int A:: *member [] = {&A::x, &A::y, &A::z}; for (int i = 0; i < 3; ++i) cout << tmp.(*member[i]);
这个用途也可以放到成员函数上,构建一个函数列表,顺序调用。
这么个指针的行为跟一般的指针显然不一样,它不保存地址,而是保存一个“偏移量”,从对象地址开头到对象成员的偏移量。这玩意其实可以输出:
struct A{ int a, b, c; }; main() { printf("%d%d%d", &A::a, &A::b, &A::c); //! 输入为0, 4, 8 //! 当然这玩意类型不是int,printf直接将他以int解析输出了,所以cout达不到效果 }
这样类成员指针的意义就很明显了,假设一个A的对象t,那么t的地址&t
和a的地址&(t.a)
是相等的,而&(t.b)
要多出来4,&(t.c)
又要多出来4。每个对象的内存构造都是一样的,这个类成员指针就是获取每个成员相对于头地址的偏移量,这样当我使用t.*member
编译器就知道是头地址+4处的变量,并且是个int。
不过成员函数又不太一样了。不同对象的成员函数只有同一份程序短代码。C++不能用&(t.fun)
的方式获取对象的成员函数的地址,要用取&A::fun
得到函数的地址。这个当然是真地址了。
类成员指针可以用于static
吗?显然不行,static成员单独存放,与类本身无关,取&A::staticmember
得到的就是这个变量的正经地址。那可以用于virtual function
吗?答案是可以,但是虚函数的地址无法确定,所以又变成了储存偏移量,实际上储存的是函数在虚表中的索引值。
补充:mem_fn
通过mem_fn对类函数成员指针进行包装,来返回一个可调用对象。使用时,包含头文件functional。
#include <iostream> #include <functional> using namespace std; class Compute { public: Compute(int a, int b) :a(a), b(b) { } int add() { return a + b; } int sub() const { return a - b; } private: int a; int b; }; int main(void) { Compute com(100, 10), *p = &com; auto fun1 = mem_fn(&Compute::add); cout << fun1(com) << endl; cout << fun1(p) << endl; auto fun2 = mem_fn(&Compute::sub); cout << fun2(com) << endl; cout << fun2(p) << endl; cin.get(); return 0; }
运行
总结