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

发布于 2024-11-18 23:03:15 字数 423 浏览 5 评论 0原文

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

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

Yes, I've seen this question and this FAQ, but I still don't understand what ->* and .* mean in C++.
Those pages provide information about the operators (such as overloading), but don't seem to explain well what they are.

What are ->* and .* in C++, and when do you need to use them as compared to -> and .?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

空‖城人不在 2024-11-25 23:03:15

我希望这个例子能让你明白一些事情

//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 中。为此,使用了特殊的成员函数指针调用语法...只需自己尝试几个示例,您就会习惯它

I hope this example will clear things for you

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

Now, you can't use x.somePointer(), or px->somePointer() because there is no such member in class X. For that the special member function pointer call syntax is used... just try a few examples yourself ,you'll get used to it

琉璃繁缕 2024-11-25 23:03:15

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

对于成员变量:

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

EDIT: By the way, it gets weird for virtual member functions pointers.

For member variables:

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;
}

Member functions are almost the same.

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 ();
}
虚拟世界 2024-11-25 23:03: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;
};

In a nutshell: You use -> and . if you know what member you want to access. And you use ->* and .* if you don't know what member you want to access.

Example with a simple intrusive list

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;
};
拥抱没勇气 2024-11-25 23:03:15

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

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 。但从概念上讲,我们正在取消引用它,就像我们取消引用普通对象指针一样。

When you have a normal pointer (to an object or a basic type), you would use * to dereference it:

int a;
int* b = a;
*b = 5;     // we use *b to dereference b, to access the thing it points to

Conceptually, we're doing the same thing with a member function pointer:

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

I hope that helps explain the concept. We're effectively dereferencing our pointer to the member function. It's a little more complicated than that -- it's not an absolute pointer to a function in memory, but just an offset, which is applied to foo or p above. But conceptually, we're dereferencing it, much like we would dereference a normal object pointer.

久而酒知 2024-11-25 23:03:15

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

您可以通过两种方式获得对象:您拥有对该对象的引用,或者您拥有指向该对象的指针。

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

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

它们遵循相当反直觉的规则,并且无需任何显式强制转换就可以绕过受保护的访问,也就是说,无意中……

干杯&呵呵,

So called "pointers" to members in C++ are more like offsets, internally. You need both such a member "pointer", and an object, to reference the member in the object. But member "pointers" are used with pointer syntax, hence the name.

There are two ways you can have an object at hand: you have a reference to the object, or you have a pointer to the object.

For the reference, use .* to combine it with a member pointer, and for the pointer, use ->* to combine it with a member pointer.

However, as a rule, don't use member pointers if you can avoid it.

They obey pretty counter-intuitive rules, and they make it possible to circumvent protected access without any explicit casting, that is, inadvertently…

Cheers & hth.,

说好的呢 2024-11-25 23:03:15

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

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

例如,考虑 Foo 类:

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

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

int Foo::* iPtr;

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

iPtr = &Foo::i;

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

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

Foo foo;
Foo* fooPtr = &foo;

然后,您可以结合 foo 取消引用 iPtrfooPtr

foo.*iPtr = 0;
fooPtr->*iPtr = 0;

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

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

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

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

C++17 — 使用 std::invoke() 代替

自 C++17 起,这两个运算符的使用都可以替换为 std::invoke 函数模板。 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

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

Pointer-to-member access operators: .* and ->*

The pointer-to-member access operators, .* and ->*, are for dereferencing a pointer to member in combination with an object and a pointer to object, respectively. This description applies to both pointers to data members and pointers to member functions.

For example, consider the class Foo:

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

If you declare a member pointer, iPtr, to an int data member of Foo:

int Foo::* iPtr;

You can initialize this member pointer iPtr so that it points to the Foo::i member:

iPtr = &Foo::i;

To dereference this pointer, you need to use it in conjunction with a Foo object.

Consider now the object foo and the pointer to object fooPtr:

Foo foo;
Foo* fooPtr = &foo;

Then, you can dereference iPtr in combination with foo or fooPtr:

foo.*iPtr = 0;
fooPtr->*iPtr = 0;

Analogously, you can use .* and ->* with pointers to function members. Note however that you will need to enclose them between parentheses because the function call operator, i.e., (), has higher precedence than both .* and ->*:

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

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

To conclude: you need an object to dereference a pointer to a member, and which one you use, either .* or ->* for dereferencing the pointer to member, depends on whether this needed object is directly provided or through an object pointer.

C++17 — Using std::invoke() instead

The use of both operators can be replaced since C++17 by the std::invoke function template. std::invoke provides a unified way of dereferencing member pointers regardless of whether you use them in combination with an object or an object pointer, and also regardless of whether the pointer to member corresponds to a pointer to data member or pointer to member function:

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

This unified syntax corresponds to the ordinary function call syntax, and it may make it easier to write generic code.

七月上 2024-11-25 23:03:15

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

考虑使用 functionbindstd::boost::,具体取决于您是否编写 C++ 03 或 0x)而不是那些。

You cannot dereference pointer to members as normal pointers — because member functions require this pointer, and you have to pass it somehow. So, you need to use these two operators, with object on one side, and pointer on another, e.g. (object.*ptr)().

Consider using function and bind (std:: or boost::, depending on whether you write C++03 or 0x) instead of those, though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文