C++中指向成员的指针运算符 ->* 和 .* 是什么?
What are the pointer-to-member operators ->* and .* in C++?
是的,我看过这个问题和这个常见问题解答,但我仍然不明白->*
和.*
在C++中的含义
这些页面提供了有关运算符(如重载)的信息,但似乎没有很好地解释它们是什么。
C++中的->*
和.*
是什么?与->
和.
相比,何时需要使用它们?
我希望这个例子能为你澄清
//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中没有这样的成员。为此,使用了特殊的成员函数指针调用语法。。。只要自己尝试几个例子,你就会习惯
EDIT:顺便说一句,虚拟成员函数指针会变得很奇怪。
对于成员变量:
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
访问,也就是说,无意中…
干杯&hth。,
当您有一个普通指针(指向对象或基本类型)时,您将使用*
来取消引用它:
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
。但从概念上讲,我们正在取消对它的引用,就像我们取消对普通对象指针的引用一样。
不能将指向成员的指针作为普通指针来取消引用,因为成员函数需要this
指针,并且必须以某种方式传递它。因此,您需要使用这两个运算符,对象在一侧,指针在另一侧,例如(object.*ptr)()
。
不过,请考虑使用function
和bind
(std::
或boost::
,具体取决于您是编写C++03还是0x)来代替它们。
指向成员访问运算符的指针:.*
和->*
指向成员访问运算符的指针.*
和->*
用于分别将指向成员的指针与指向对象和的指针组合取消引用。此描述既适用于指向数据成员的指针,也适用于指向成员函数。
例如,考虑类Foo
:
struct Foo {
int i;
void f();
};
如果您声明一个指向Foo
:的int
数据成员的成员指针iPtr
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)();
总之:您需要一个对象来取消引用指向成员的指针,而您使用哪一个对象(.*
或->*
)来取消引用到成员的指针取决于此所需对象是直接提供的还是通过对象指针提供的。
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
这种统一的语法对应于普通的函数调用语法,它可能会使编写泛型代码变得更容易。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- C++避免重复声明的语法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- C++中名称篡改的目的是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 派生类销毁的最佳实践是什么
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 通过JNI传递数据数组的最快方法是什么
- "using namespace std;"在C++的作用是什么?
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 文件系统:复制功能的速度秘诀是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 使用 std::vector<boost::shared_ptr<Base_Class>> 或 boost::p tr_vector 的性能注意事项是什么<Base>