是的,我已经看到了这个问题,而 这个常见问题,但我还是不明白->*
,并.*
用C ++的意思。
这些页面提供有关运算符的(例如重载),但似乎并不能很好地解释它们是什么。
什么是->*
和.*
C ++中,当你需要使用它们相比,为->
和.
?
Answers:
我希望这个例子能为您清除一切
//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中没有这样的成员。为此,使用了特殊的成员函数指针调用语法...您自己尝试一些示例,您就会习惯了
pointer
与普通函数指针有何不同,它需要不同的语法?(例如,它更大吗?)
&X::f
运作方式?看到这个问题。
编辑:顺便说一下,它对于虚拟成员函数指针很奇怪。
对于成员变量:
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 ();
}
简而言之:您使用->
,.
如果知道要访问的成员。而你使用->*
,.*
如果你不知道要访问哪个成员。
简单的侵入式列表示例
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 ++成员“指针”更像是偏移量。您既需要这样的成员“指针”,也需要一个对象,以引用该对象中的成员。但是成员“指针”与指针语法一起使用,因此也称为名称。
可以使用两种方法获取对象:具有对该对象的引用,或者具有指向该对象的指针。
对于引用,.*
将其与成员指针结合使用,对于指针,->*
将其与成员指针结合使用。
但是,通常,如果可以避免,请勿使用成员指针。
他们遵循相当违反直觉的规则,并且可以绕过protected
访问而无需任何明确的强制转换,也就是说,无意间……
干杯,……
当拥有普通指针(指向对象或基本类型)时,可以使用*
取消引用的方式:
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
更高版本。但是从概念上讲,我们正在取消引用它,就像我们将取消引用普通对象指针一样。
.*
和->*
指针到成员访问运营商,.*
和->*
,是用于解引用指针构件结合的对象和指针的对象,分别。此说明适用于指向数据成员的指针和指向成员函数的指针。
例如,考虑类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;
类似地,您可以使用.*
和->*
与函数成员的指针。但是请注意,由于函数调用运算符(即)的()
优先级高于.*
和,因此您需要将它们括在括号中->*
:
void (Foo::*memFuncPtr)() = &Foo::f;
(foo.*memFuncPtr)();
(fooPtr->*memFuncPtr)();
结论:您需要一个对象来解除对成员的指针的引用,而使用哪个对象.*
或->*
解除对成员的指针的引用,取决于该所需对象是直接提供还是通过对象指针提供。
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
此统一语法与普通函数调用语法相对应,并且可以使编写通用代码更容易。