What are the Pointer-to-Member ->* and .* Operators in C++?
是的,我已经看到了这个问题和常见问题解答,但是我仍然不明白
这些页面提供了有关运算符的信息(例如重载),但似乎并不能很好地解释它们是什么。
什么是C ++中的
我希望这个例子能为您清除一切
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //we have a class struct X { void f() {} void g() {} }; typedef void (X::*pointer)(); //ok, let's take a pointer and assign f to it. pointer somePointer = &X::f; //now I want to call somePointer. But for that, I need an object X x; //now I call the member function on x like this (x.*somePointer)(); //will call x.f() //now, suppose x is not an object but a pointer to object X* px = new X; //I want to call the memfun pointer on px. I use ->* (px ->* somePointer)(); //will call px->f(); |
现在,您不能使用
编辑:顺便说一下,它对于虚拟成员函数指针很奇怪。
对于成员变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | struct Foo { int a; int b; }; int main () { Foo foo; int (Foo :: * ptr); ptr = & Foo :: a; foo .*ptr = 123; // foo.a = 123; ptr = & Foo :: b; foo .*ptr = 234; // foo.b = 234; } |
成员功能几乎相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | struct Foo { int a (); int b (); }; int main () { Foo foo; int (Foo :: * ptr) (); ptr = & Foo :: a; (foo .*ptr) (); // foo.a (); ptr = & Foo :: b; (foo .*ptr) (); // foo.b (); } |
简而言之:如果知道要访问的成员,则使用
简单的侵入式列表示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | template<typename ItemType> struct List { List(ItemType *head, ItemType * ItemType::*nextMemPointer) :m_head(head), m_nextMemPointer(nextMemPointer) { } void addHead(ItemType *item) { (item ->* m_nextMemPointer) = m_head; m_head = item; } private: ItemType *m_head; // this stores the member pointer denoting the //"next" pointer of an item ItemType * ItemType::*m_nextMemPointer; }; |
在内部,所谓的C ++成员的"指针"更像是偏移量。您既需要这样的成员"指针",也需要对象,以引用该对象中的成员。但是成员"指针"与指针语法一起使用,因此也称为名称。
可以使用两种方法获取对象:具有对对象的引用,或具有指向对象的指针。
对于参考,使用
但是,通常,如果可以避免,请勿使用成员指针。
它们遵循相当违反直觉的规则,并且可以绕过
干杯,……
当具有普通指针(指向对象或基本类型)时,可以使用
1 2 3 | int a; int* b = a; *b = 5; // we use *b to dereference b, to access the thing it points to |
从概念上讲,我们使用成员函数指针执行相同的操作:
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 | class SomeClass { public: void func() {} }; // typedefs make function pointers much easier. // this is a pointer to a member function of SomeClass, which takes no parameters and returns void typedef void (SomeClass::*memfunc)(); memfunc myPointer = &SomeClass::func; SomeClass foo; // to call func(), we could do: foo.func(); // to call func() using our pointer, we need to dereference the pointer: foo.*myPointer(); // this is conceptually just: foo . *myPointer (); // likewise with a pointer to the object itself: SomeClass* p = new SomeClass; // normal call func() p->func(); // calling func() by dereferencing our pointer: p->*myPointer(); // this is conceptually just: p -> *myPointer (); |
我希望这有助于解释这个概念。我们正在有效地取消引用指向成员函数的指针。除此之外,它还有些复杂-它不是内存中函数的绝对指针,而只是一个偏移量,该偏移量适用于上述
您不能将成员的指针作为普通指针取消引用-因为成员函数需要
可以考虑使用
指向成员的指针访问运算符:
指向成员的指针访问运算符
例如,考虑类
1 2 3 4 | struct Foo { int i; void f(); }; |
如果将成员指针
1 | int Foo::* iPtr; |
您可以初始化此成员指针
1 | iPtr = &Foo::i; |
要取消引用此指针,您需要将其与
现在考虑对象
1 2 | Foo foo; Foo* fooPtr = &foo; |
然后,您可以结合
1 2 | foo.*iPtr = 0; fooPtr->*iPtr = 0; |
类似地,您可以将
1 2 3 4 | void (Foo::*memFuncPtr)() = &Foo::f; (foo.*memFuncPtr)(); (fooPtr->*memFuncPtr)(); |
结论:您需要一个对象来解除对成员的指针的引用,并且使用哪个对象(
C ++ 17 —改为使用
从C ++ 17开始,可以将两个运算符的使用替换为
1 2 3 4 5 6 7 | // dereference a pointer to a data member std::invoke(iPtr, foo) = 0; // with an object std::invoke(iPtr, fooPtr) = 0; // with an object pointer // dereference a pointer to a member function std::invoke(memFuncPtr, foo); // with an object std::invoke(memFuncPtr, fooPtr); // with an object pointer |
此统一语法与普通函数调用语法相对应,并且可以使编写通用代码更容易。