是的,我看过this question和 this FAQ(错误的链接) this FAQ,但我仍然没有了解C ++中->*
和.*
的含义
这些页面提供了关于运算符的信息(例如重载),但似乎并没有很好地解释它们是什么。
C ++中的->*
和.*
是什么,与->
和.
相比,您何时需要使用它们?
答案 0 :(得分:65)
我希望这个例子能为你清楚
//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();
现在,你不能使用x.somePointer()
或px->somePointer()
,因为在类X中没有这样的成员。为此,使用了特殊的成员函数指针调用语法...只是尝试一下例子你自己,你会习惯它
答案 1 :(得分:18)
编辑:顺便说一下,virtual member functions pointers会变得奇怪。
对于成员变量:
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;
}
会员功能几乎相同。
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 ();
}
答案 2 :(得分:11)
简而言之:如果您知道要访问的成员,请使用->
和.
。如果不知道您要访问的成员,则可以使用->*
和.*
。
带有简单侵入列表的示例
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;
};
答案 3 :(得分:7)
在C ++中对成员的所谓“指针”更像内部的偏移。您需要这样的成员“指针”和对象,以引用对象中的成员。但成员“指针”与指针语法一起使用,因此名称。
手头有两种方法:你有一个对象的引用,或者你有一个指向对象的指针。
对于参考,使用.*
将其与成员指针组合,对于指针,使用->*
将其与成员指针组合。
但是,作为一项规则,如果可以避免使用成员指针,请不要使用它。
他们遵守相反的反直觉规则,他们可以在没有任何明确投射的情况下绕过protected
访问,即无意中...
干杯&amp;第h。,
答案 4 :(得分:5)
你不能将指向成员的指针解引用为普通指针 - 因为成员函数需要this
指针,你必须以某种方式传递它。因此,您需要使用这两个运算符,一方面是对象,另一方面是指针,例如(object.*ptr)()
。
考虑使用function
和bind
(std::
或boost::
,具体取决于您是编写C ++ 03还是0x)而不是那些。
答案 5 :(得分:5)
当你有一个普通指针(对象或基本类型)时,你可以使用*
取消引用它:
int a;
int* b = a;
*b = 5; // we use *b to dereference b, to access the thing it points to
从概念上讲,我们使用成员函数指针执行相同的操作:
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 ();
我希望这有助于解释这个概念。我们实际上是取消引用指向成员函数的指针。它有点复杂 - 它不是指向内存中函数的绝对指针,而只是一个偏移量,它适用于上面的foo
或p
。但从概念上讲,我们正在取消引用它,就像我们取消引用普通对象指针一样。
答案 6 :(得分:1)
.*
和->*
指向成员的指针访问运算符.*
和->*
用于将指向成员的指针与对象结合使用和指向对象的指针。此说明适用于指向数据成员的指针和指向成员函数的指针。
例如,考虑类Foo
:
struct Foo {
int i;
void f();
};
如果您声明指向iPtr
的{{1}}数据成员的成员指针int
:
Foo
您可以初始化此成员指针int Foo::* iPtr;
,使其指向iPtr
成员:
Foo::i
要取消引用此指针,您需要将其与iPtr = &Foo::i;
对象结合使用。
现在考虑对象Foo
和指向对象foo
的指针:
fooPtr
然后,您可以将Foo foo;
Foo* fooPtr = &foo;
或iPtr
与foo
一起取消引用:
fooPtr
类似地,您可以将foo.*iPtr = 0;
fooPtr->*iPtr = 0;
和.*
与指向函数成员的指针一起使用。但是请注意,由于函数调用运算符(即->*
的优先级要高于()
和.*
,因此您需要将它们括在括号之间:< / p>
->*
总结:您需要一个对象来解除对成员的指针的引用,而使用void (Foo::*memFuncPtr)() = &Foo::f;
(foo.*memFuncPtr)();
(fooPtr->*memFuncPtr)();
或.*
来解除对成员的指针的引用取决于该所需对象是否为直接提供或通过对象指针。
->*
从C ++ 17开始,可以使用std::invoke
函数模板来代替使用两个运算符。 std::invoke()
提供了一种取消引用成员指针的统一方法,无论您是将它们与 object 还是 object指针结合使用,以及无论< em>指向成员的指针对应于指向数据成员的指针或指向成员函数的指针:
std::invoke
此统一语法与普通函数调用语法相对应,可以使编写通用代码更容易。