Что такое операторы Pointer-to-Member -> * и. * В C ++? - PullRequest
57 голосов
/ 05 июля 2011

Да, я видел этот вопрос и этот FAQ (неправильная ссылка) этот FAQ , но я до сих пор не понимают, что ->* и .* означают в C ++.
Эти страницы предоставляют информацию о операторах (таких как перегрузка), но, похоже, не очень хорошо объясняютчто они являются .

Что такое ->* и .* в C ++, и когда вам нужно их использовать по сравнению с -> и .?

Ответы [ 6 ]

66 голосов
/ 05 июля 2011

Я надеюсь, что этот пример прояснит для вас вещи

//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 такого члена нет. Для этого специальныйиспользуется синтаксис вызова указателя на функцию-член ... просто попробуйте несколько примеров сами, вы привыкнете к этому

18 голосов
/ 05 июля 2011

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 ();
}
11 голосов
/ 05 июля 2011

В двух словах: вы используете -> и ., если знаете, к какому участнику вы хотите получить доступ.И вы используете ->* и .*, если вы не знаете, к какому участнику вы хотите получить доступ.

Пример с простым навязчивым списком

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;
};
7 голосов
/ 05 июля 2011

Так называемые «указатели» на члены в C ++ больше похожи на внутренние смещения.Вам нужен и такой «указатель» члена, и объект, чтобы ссылаться на член в объекте.Но члены-указатели используются с синтаксисом указателя, отсюда и название.

Существует два способа, которыми вы можете иметь объект под рукой: у вас есть ссылка на объект или у вас есть указатель на объект.

Для справки используйте .*, чтобы объединить его с указателем члена, а для указателя используйте ->*, чтобы объединить его с указателем члена.

Однако, как правило,, не используйте указатели членов, если вы можете избежать этого.

Они подчиняются довольно нелогичным правилам, и они позволяют обойти protected доступ без какого-либо явного приведения, то есть непреднамеренно ...

Приветствия & hth.,

5 голосов
/ 05 июля 2011

Когда у вас есть нормальный указатель (на объект или базовый тип), вы можете использовать * для разыменования его:

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 голосов
/ 05 июля 2011

Вы не можете разыменовать указатель на элементы как обычные указатели - потому что функции-члены требуют указатель this, и вам нужно как-то передать его. Итак, вам нужно использовать эти два оператора, с объектом на одной стороне и указателем на другой, например, (object.*ptr)().

Рассмотрите возможность использования function и bind (std:: или boost::, в зависимости от того, пишете ли вы C ++ 03 или 0x) вместо них.

...