はい、私はこの質問と このFAQを見ましたが、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にそのようなメンバーがないためです。そのために、特別なメンバー関数ポインター呼び出し構文が使用されます...いくつかの例を自分で試してみてください。慣れます。
編集:ちなみに、仮想メンバー関数のポインターでは奇妙になります。
メンバー変数の場合:
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 ++のメンバーへのいわゆる「ポインタ」は、内部的にはオフセットのようなものです。オブジェクト内のメンバーを参照するには、そのようなメンバー「ポインター」とオブジェクトの両方が必要です。ただし、メンバーの「ポインター」はポインター構文で使用されるため、この名前が付けられています。
オブジェクトを手元に置くには、2つの方法があります。オブジェクトへの参照があるか、オブジェクトへのポインタがあります。
参照の場合は、を使用.*
してメンバーポインターと結合し、ポインターの場合は、を使用->*
してメンバーポインターと結合します。
ただし、原則として、回避できる場合はメンバーポインタを使用しないでください。
それらはかなり直感に反するルールに従い、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
ポインターが必要であり、何らかの方法でそれを渡す必要があるためです。したがって、これらの2つの演算子を使用する必要があります。一方の側にオブジェクトがあり、もう一方の側にポインタがあります(object.*ptr)()
。
function
ただし、それらの代わりにand bind
(std::
またはboost::
、C ++ 03と0xのどちらを書くかによって異なります)を使用することを検討してください。
.*
および->*
メンバーへのポインター・アクセス演算子、.*
およびは、それぞれ、オブジェクトおよびオブジェクトへのポインターと組み合わせて、メンバーへのポインターを->*
逆参照するためのものです。この説明は、データメンバーへのポインターとメンバー関数へのポインターの両方に適用されます。
たとえば、次のクラスについて考えてみ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()
代わりに使用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
この統一された構文は、通常の関数呼び出し構文に対応しており、ジェネリックコードの記述が容易になる場合があります。