C++中的指针成员 - >*和.*运算符是什么?

Meh*_*dad 59 c++ operators pointer-to-member operator-arrow-star

是的,我已经看到了这个问题,这个FAQ(错误的链接) 这个常见问题,但我还是不明白->*,并.*用C++的意思.
这些页面提供了有关运算符的信息(例如重载),但似乎并不能很好地解释它们什么.

什么是->*.*C++,你什么时候需要使用它们->.?相比?

Arm*_*yan 67

我希望这个例子能为你清楚

//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();
Run Code Online (Sandbox Code Playgroud)

现在,你不能使用x.somePointer(),或者px->somePointer()因为在类X中没有这样的成员.为此使用特殊的成员函数指针调用语法...只是自己尝试一些例子,你会习惯它

  • 将其视为一个“相对”指针:相对于一个对象——然后您必须提供该指针才能真正到达最终目的地。 (3认同)
  • 添加**所需的**额外大括号以补偿运算符优先级. (2认同)
  • @Armen:哦,我看到现在发生了什么......我以前从未见过或不需要这样的东西.这很酷(+1),但我想现在的问题是:`指针`与普通函数指针有什么不同,它需要不同的语法?(例如它更大吗?) (2认同)

spr*_*aff 19

编辑:顺便说一句,虚拟成员函数指针变得奇怪.

对于成员变量:

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;
}
Run Code Online (Sandbox Code Playgroud)

成员函数几乎相同.

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 ();
}
Run Code Online (Sandbox Code Playgroud)

  • +1表示语法适用于所有成员,而不仅仅是成员函数.我发现尽管有许多相当有趣的潜在应用程序,但很少使用指向成员变量的指针. (3认同)

Joh*_*itb 13

简而言之:您使用->并且.如果您知道要访问的成员.并且使用->*.*,如果你知道你要访问哪些成员.

带有简单侵入列表的示例

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;
};
Run Code Online (Sandbox Code Playgroud)

  • 对于第一句话+1,虽然从来没有在我的生活中,我*不知道我想要访问哪个成员,哈哈.:) (6认同)

眠りネ*_*ネロク 9

指向成员的指针访问运算符:.*->*

\n

指向成员的指针访问运算符.*->*分别用于取消引用指向成员的指针与对象指向对象的指针的组合。此描述适用于指向数据成员的指针指向成员函数的指针

\n

例如,考虑一下类Foo

\n
struct Foo {\n   int i;\n   void f();\n};\n
Run Code Online (Sandbox Code Playgroud)\n

如果您声明一个指向的数据成员的成员iPtr指针:intFoo

\n
int Foo::* iPtr;\n
Run Code Online (Sandbox Code Playgroud)\n

您可以初始化该成员指针iPtr,使其指向Foo::i成员:

\n
iPtr = &Foo::i;\n
Run Code Online (Sandbox Code Playgroud)\n

要取消引用该指针,您需要将其与对象结合使用Foo

\n

现在考虑对象foo和指向对象的指针fooPtr

\n
Foo foo;\nFoo* fooPtr = &foo;\n
Run Code Online (Sandbox Code Playgroud)\n

然后,您可以iPtr结合使用fooor取消引用fooPtr

\n
foo.*iPtr = 0;\nfooPtr->*iPtr = 0;\n
Run Code Online (Sandbox Code Playgroud)\n

类似地,您可以将.*and->*指向函数成员的指针一起使用。但请注意,您需要将它们括在括号内,因为函数调用运算符(即 )()的优先级高于.*->*

\n
void (Foo::*memFuncPtr)() = &Foo::f;\n\n(foo.*memFuncPtr)();\n(fooPtr->*memFuncPtr)();\n
Run Code Online (Sandbox Code Playgroud)\n

总而言之:您需要一个对象来取消引用指向成员的指针,而使用哪个对象来.*取消->*引用指向成员的指针,取决于是直接提供还是通过对象指针提供所需的对象。

\n

C++17 \xe2\x80\x94 使用std::invoke()代替

\n

自 C++17 起,这两个运算符的使用都可以由std::invoke函数模板替换。提供了一种统一的方式来取消引用成员指针,无论您是否将它们与对象对象指针std::invoke结合使用,也无论指向成员的指针是否对应于指向数据成员的指针指向成员函数的指针

\n
// dereference a pointer to a data member\nstd::invoke(iPtr, foo) = 0;      // with an object\nstd::invoke(iPtr, fooPtr) = 0;   // with an object pointer\n\n// dereference a pointer to a member function\nstd::invoke(memFuncPtr, foo);      // with an object\nstd::invoke(memFuncPtr, fooPtr);   // with an object pointer\n
Run Code Online (Sandbox Code Playgroud)\n

这种统一的语法对应于普通的函数调用语法,可能会让编写通用代码变得更加容易。

\n


Che*_*Alf 7

所谓的C++成员"指针"更像内部的偏移.您需要这样的成员"指针"和对象,以引用对象中的成员.但成员"指针"与指针语法一起使用,因此名称.

有两种方法可以让手头有一个对象:你有一个对象的引用,或者你有一个指向对象的指针.

作为参考,用于.*将其与成员指针组合,对于指针,用于->*将其与成员指针组合.

但是,通常,如果可以避免使用成员指针,请不要使用它.

他们遵守相反的反直觉规则,他们可以在protected没有任何明确的投射的情况下规避访问,也就是说,无意中......

干杯&hth.,

  • @Mehrdad:如果您可以有一个指向仅限于非虚拟成员函数的成员函数的指针,那么它确实可能只是地址。然而,虚拟与否不是成员函数指针类型的一部分。因此,它的表示需要包括一些关于当前值是否引用虚拟函数的信息,如果是虚拟函数,则需要包含基于 vtable 的实现信息,该信息确定与指针类型关联的类的 vtable 中的偏移量。 (2认同)

Cat*_*lus 5

您不能将成员的指针作为普通指针取消引用-因为成员函数需要this指针,并且您必须以某种方式传递它。因此,您需要使用这两个运算符,对象在一侧,指针在另一侧,例如(object.*ptr)()

不过,请考虑使用functionand bindstd::boost::,取决于您编写的是C ++ 03还是0x)而不是那些。


Tim*_*Tim 5

当你有一个普通的指针(对象或基本类型)时,你会用*它取消引用它:

int a;
int* b = a;
*b = 5;     // we use *b to dereference b, to access the thing it points to
Run Code Online (Sandbox Code Playgroud)

从概念上讲,我们使用成员函数指针执行相同的操作:

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  ();
Run Code Online (Sandbox Code Playgroud)

我希望这有助于解释这个概念.我们实际上是取消引用指向成员函数的指针.它有点复杂 - 它不是指向内存中函数的绝对指针,而只是一个偏移量,它应用于foop超过.但从概念上讲,我们正在取消引用它,就像我们取消引用普通对象指针一样.

  • 尝试编译会出现“必须使用 '.*' 或 '-&gt;*' 来调用指向成员函数的指针...”错误。这是因为函数调用“()”优先于成员指针运算符。我认为这可以通过分别添加括号 `(foo.*myPointer)();` 和 `(p-&gt;*myPointer)();` 来解决。 (2认同)