2011-07-05 9 views
47

Sí, he visto this question y this FAQ (enlace mal) this FAQ, pero todavía No entiendo lo que quiere decir ->* y .* en C++.
Estas páginas proporcionan información sobre los operadores (tales como la sobrecarga), pero no parecen explicar bien lo que son .¿Qué son los Pointer-to-Member -> * y. * Operadores en C++?

¿Qué son ->* y .* en C++, y cuándo los necesita en comparación con -> y .?

+3

Creo que [estas preguntas frecuentes] (http://www.parashift.com/c++faq-lite/pointers-to-members.html) lo explica bastante bien. –

+0

@Rob: No puedo creer que haya publicado el enlace equivocado. ¡X___X es el que quería publicar, no MSDN! - Lo he visto, pero no entendí mucho de eso. Todo lo que dicen es que "el tipo es diferente", pero encontré ese tipo de confusión ... – Mehrdad

Respuesta

50

espero que este ejemplo se borrará cosas para usted

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

Ahora, no se puede utilizar x.somePointer(), o px->somePointer() porque no hay ningún miembro de la clase X. Para que la sintaxis especial llamada puntero de función miembro se usa ... solo pruebe algunos ejemplos, se acostumbrará

+2

Agregue las llaves adicionales ** requeridas para compensar la precedencia del operador. –

+2

@Armen: Ohh, veo lo que está sucediendo ahora ... Nunca había visto o necesitaba algo así antes. Es genial (+1), pero supongo que la pregunta ahora es: ¿En qué se diferencia 'puntero' de un puntero de función normal que requiere una sintaxis diferente? (Por ejemplo, ¿es más grande?) – Mehrdad

+0

@Mehrdad: El punto es que para llamar a una función normal, simplemente proporcione los argumentos. Pero en el caso de funciones de miembro no estáticas también necesita un objeto sobre el que desea llamar a la función. De ahí la nueva sintaxis. –

10

En pocas palabras: usted usa -> y . si sabe a qué miembro desea acceder. Y usa ->* y .* si no sabe a qué miembro desea acceder.

Ejemplo con una simple lista intrusiva

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

+1 para la primera oración, aunque nunca en mi vida he * no * conocido a qué miembro quiero acceder, jaja. :) – Mehrdad

6

Los llamados "punteros" a los miembros de C++ se parecen más a las compensaciones, a nivel interno. Necesita tanto un "puntero" miembro y un objeto para hacer referencia al miembro en el objeto. Pero los "punteros" de miembro se usan con sintaxis de puntero, de ahí el nombre.

Hay dos maneras en que puede tener un objeto a la mano: tiene una referencia al objeto o tiene un puntero al objeto.

Para la referencia, utilice .* combinarlo con un puntero miembro, y para el puntero, utilice ->* combinarlo con un puntero miembro.

Sin embargo, como norma, no utilice punteros de miembro si puede evitarlo.

Obedecen reglas bastante contraintuitivas, y permiten eludir el acceso protected sin ningún tipo de conversión explícita, es decir, inadvertidamente y hellip;

Saludos & HTH,

+0

+1 para explicarlo bien sin código. :) Pregunta: ¿Por qué no podemos simplemente tomar la dirección de la función como la de una función normal? ¿El puntero a una función miembro es diferente de un puntero a alguna otra función? (Por ejemplo, ¿es más grande?) – Mehrdad

+1

@Mehrdad: Si pudiera tener un puntero a la función de miembro que estuviera restringido a las funciones de miembro no virtual, podría ser simplemente la dirección. Sin embargo, la virtualidad o no es parte del tipo de puntero de función miembro. Y entonces su representación necesita incluir cierta información sobre si el valor actual se refiere a una función virtual o no, y si es virtual, para una información de implementación basada en vtable que determina un desplazamiento en el vtable de la clase con la que está asociado el tipo de puntero. –

4

no se puede referencia a un puntero a los miembros como punteros normales -. Porque requieren funciones miembro this puntero, y usted tiene que pasar de alguna manera. Por lo tanto, debe usar estos dos operadores, con el objeto en un lado y el puntero en otro, p. (object.*ptr)().

considerar el uso de function y bind (std:: o boost::, dependiendo de si se escribe C++ 0x o 03) en lugar de los que, sin embargo.

+0

Creo que esta puede ser la mejor explicación aquí. – Marcin

18

EDITAR: Por cierto, se pone raro para virtual member functions pointers.

Para variables miembro:

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

Las funciones miembro son casi los mismos.

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(); 
} 
+2

+1 para mostrar que la sintaxis se aplica a todos los miembros, no solo a las funciones de miembro. Sin embargo, encuentro que los punteros a las variables de miembro se usan muy raramente, a pesar de sus muchas aplicaciones potenciales bastante interesantes. –

5

Cuando usted tiene un puntero normal (a un objeto o un tipo básico), se utiliza para eliminar la referencia *:

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

Conceptualmente, estamos haciendo lo mismo con un miembro indicador de función:

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

Espero que esto ayude a explicar el concepto. Estamos efectivamente desreferenciando nuestro puntero a la función miembro. Es un poco más complicado que eso: no es un puntero absoluto a una función en la memoria, sino solo un desplazamiento, que se aplica a foo o p arriba. Pero conceptualmente, estamos desreferenciando, al igual que eliminaríamos un puntero de objeto normal.

Cuestiones relacionadas