83

是的,我已经看过这个问题这个常见问题解答,但我仍然不明白C++ 中的含义->*.*含义。
这些页面提供了有关运算符的信息(例如重载),但似乎没有很好地解释它们什么。

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

4

7 回答 7

92

我希望这个例子能为你清除一切

//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中没有这样的成员。为此使用了特殊的成员函数指针调用语法......你自己试试几个例子,你会习惯的

于 2011-07-05T17:04:36.893 回答
25

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

对于成员变量:

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 ();
}
于 2011-07-05T17:07:52.383 回答
15

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

带有简单侵入性列表的示例

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;
};
于 2011-07-05T17:06:04.190 回答
8

所谓的 C++ 中成员的“指针”在内部更像是偏移量。您需要这样的成员“指针”和对象来引用对象中的成员。但是成员“指针”与指针语法一起使用,因此得名。

有两种方法可以获取手头的对象:获取对象的引用,或者获取对象的指针。

对于引用,使用.*它与成员指针组合,对于指针,使用->*它与成员指针组合。

但是,作为一项规则,如果可以避免,请不要使用成员指针。

它们遵循非常违反直觉的规则,并且它们可以在protected没有任何显式强制转换的情况下规避访问,也就是说,不经意间......

干杯&hth.,

于 2011-07-05T17:06:41.607 回答
8

当您有一个普通指针(指向一个对象或基本类型)时,您可以使用*它来取消引用它:

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  ();

我希望这有助于解释这个概念。我们有效地取消了指向成员函数的指针。它比这要复杂一些——它不是一个指向内存中函数的绝对指针,而只是一个偏移量,它被应用到foop以上。但从概念上讲,我们取消引用它,就像我们取消引用普通对象指针一样。

于 2011-07-05T17:18:09.277 回答
5

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

不过,请考虑使用functionand bind( std::or boost::,具体取决于您编写 C++03 还是 0x) 而不是那些。

于 2011-07-05T17:07:50.980 回答
2

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

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

例如,考虑类Foo

struct Foo {
   int i;
   void f();
};

如果将成员指针 , 声明iPtr为 的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;

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

void (Foo::*memFuncPtr)() = &Foo::f;

(foo.*memFuncPtr)();
(fooPtr->*memFuncPtr)();

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

C++17 —std::invoke()改为使用

std::invoke从 C++17 开始,函数模板可以替换这两个运算符的使用。std::invoke提供一种统一的解除引用成员指针的方法,无论您是与对象还是对象指针结合使用,也不管指向成员的指针对应于指向数据成员的指针还是指向成员函数的指针:

// 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

这种统一的语法对应于普通的函数调用语法,可能更容易编写泛型代码。

于 2020-08-19T09:54:04.087 回答