web-dev-qa-db-fra.com

Que sont les opérateurs Pointer-to-Member -> * et. * En C ++?

Oui, j'ai vu cette question et cette FAQ (mauvais lien)cette FAQ , mais je toujours ne comprends pas ce que ->* et .* signifie en C++.
Ces pages fournissent des informations sur les opérateurs (comme la surcharge), mais ne semblent pas bien expliquer ce qu'ils sont .

Que sont ->* et .* en C++, et quand devez-vous les utiliser par rapport à -> et .?

62
user541686

J'espère que cet exemple clarifiera les choses pour vous

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

Maintenant, vous ne pouvez pas utiliser x.somePointer() ou px->somePointer() car il n'y a pas de membre de ce type dans la classe X. Pour cela, la syntaxe d'appel du pointeur de fonction membre spécial est utilisée ... essayez simplement un quelques exemples vous-même, vous vous y habituerez

66
Armen Tsirunyan

EDIT: Au fait, cela devient bizarre pour pointeurs des fonctions membres virtuelles .

Pour les variables membres:

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

Les fonctions des membres sont presque les mêmes.

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

En bref: vous utilisez -> et . si vous savez à quel membre vous souhaitez accéder. Et vous utilisez ->* et .* si vous ne pas savez à quel membre vous souhaitez accéder.

Exemple avec une simple liste intrusive

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

Les soi-disant "pointeurs" vers les membres en C++ sont plus comme des décalages, en interne. Vous avez besoin à la fois d'un tel "pointeur" de membre et d'un objet pour référencer le membre dans l'objet. Mais les "pointeurs" membres sont utilisés avec la syntaxe des pointeurs, d'où le nom.

Il y a deux façons d'avoir un objet à portée de main: vous avez une référence à l'objet, ou vous avez un pointeur sur l'objet.

Pour la référence, utilisez .* pour le combiner avec un pointeur membre, et pour le pointeur, utilisez ->* pour le combiner avec un pointeur membre.

Cependant, en règle générale, n'utilisez pas de pointeurs membres si vous pouvez l'éviter.

Ils obéissent à des règles assez contre-intuitives, et permettent de contourner l'accès à protected sans casting explicite, c'est-à-dire par inadvertance…

Santé et hth.,

7

Lorsque vous avez un pointeur normal (vers un objet ou un type de base), vous utilisez * pour le déréférencer:

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

Conceptuellement, nous faisons la même chose avec un pointeur de fonction membre:

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

J'espère que cela explique le concept. Nous déréférençons efficacement notre pointeur sur la fonction membre. C'est un peu plus compliqué que cela - ce n'est pas un pointeur absolu vers une fonction en mémoire, mais juste un décalage, qui est appliqué à foo ou p ci-dessus. Mais conceptuellement, nous le déréférençons, tout comme nous déréférencerions un pointeur d'objet normal.

5
Tim

Vous ne pouvez pas déréférencer le pointeur sur des membres en tant que pointeurs normaux, car les fonctions membres nécessitent un pointeur this et vous devez le transmettre d'une manière ou d'une autre. Donc, vous devez utiliser ces deux opérateurs, avec un objet d'un côté et un pointeur de l'autre, par exemple (object.*ptr)().

Pensez à utiliser function et bind (std:: ou boost::, selon que vous écrivez C++ 03 ou 0x) au lieu de ceux-ci, cependant.

5
Cat Plus Plus