web-dev-qa-db-ja.com

C ++のポインター-メンバー-> *および。*演算子とは何ですか?

はい、見ました この質問 および このFAQ (間違ったリンク) このFAQ ですが、C++での->*.*の意味がわかりませんstill
これらのページは演算子について演算子(オーバーロードなど)を提供しますが、演算子が何であるかを十分に説明していないようです

C++での->*および.*とは何ですか。また、->および.と比較してこれらをいつ使用する必要がありますか?

62
user541686

この例があなたのために物事を明確にすることを願っています

_//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にはそのようなメンバーがないため、x.somePointer()またはpx->somePointer()を使用できません。そのために、特別なメンバー関数ポインター呼び出し構文が使用されています...いくつかの例を自分で、あなたはそれに慣れるでしょう

66
Armen Tsirunyan

編集:ちなみに、それは virtual member functions pointers に対して奇妙になります。

メンバー変数の場合:

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

簡単に言えば、あなたは->および.アクセスするメンバーがわかっている場合。そして、あなたは->*および.*もしあなたわからないあなたがアクセスしたいメンバーを知っている。

単純な侵入型リストの例

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に適用されるオフセットです。しかし、概念的には、通常のオブジェクトポインターを逆参照するように、逆参照しています。

5
Tim

メンバーへのポインターを通常のポインターとして逆参照することはできません。メンバー関数にはthisポインターが必要であり、何らかの方法で渡す必要があるためです。したがって、これらの2つの演算子を使用する必要があります。片側にオブジェクト、もう一方にポインタを使用します。 (object.*ptr)()

functionおよびbindstd::またはboost::、ただし、C++ 03と0xのどちらを書くかによって異なりますが)。

5
Cat Plus Plus