2012-06-12 12 views
6

Estaba pasando por un article por Don Clugston en Codeproject. Es un hermoso artículo y es bastante famoso. En el siguiente fragmento de código, he encontrado una noción particular muy difícil de comprender:Punteros de función

class A { 
public: 
     virtual int Afunc() { return 2; }; 
}; 

class B { 
public: 
     int Bfunc() { return 3; }; 
}; 

// C is a single inheritance class, derives only from A 
class C: public A { 
public: 
    int Cfunc() { return 4; }; 
}; 

// D uses multiple inheritance 
class D: public A, public B { 
public: 
    int Dfunc() { return 5; }; 
}; 

El fragmento es seguido por el siguiente párrafo:

Supongamos que crea un puntero de función miembro de la clase C. En este ejemplo , Afunc y Cfunc son funciones miembro de C, por lo que nuestro puntero a la función puede señalar a Afunc o Cfunc. Pero Afunc necesita un puntero que apunta a C :: A (que llamaré Athis), mientras Cfunc necesita un puntero que apunta a C (que llamaré Cthis). Los escritores de compiladores lidian con esta situación por un truco: aseguran que A se almacena físicamente al inicio de C. Esto significa que Athis == Cthis. Solo tenemos uno de qué preocuparse, y todo está bien con el mundo.

Lo único y lo que quiero entender es la línea en negrita y en inglés en el párrafo anterior.

no comprendo totalmente Afunc necesita un puntero a C :: Un mientras Cfunc necesita un puntero a C es muy natural.

Cualquier ayuda sería apreciada.

Respuesta

9

Llamando a una función miembro en C++, lo que ocurre internamente es que la instancia se pasa como un primer argumento oculto (tenga en cuenta que este comportamiento es estrictamente definido por la implementación, sin embargo. El estándar C++ no tiene nada que decir sobre este tema , es sólo una forma muy común de implementarlo):

x.f(y); // is treated internally as: 
f(&x, y); 

Este primer argumento es entonces disponible a través del puntero this.

ahora, Afunc en el ejemplo anterior internamente tiene la firma void Afunc(A* const this) mientras CFunc tiene la firma interna void CFunc(C* const this).

Tenga en cuenta que los tipos de argumentos en ambos casos son diferentes, por lo que cuando llama a las funciones en el mismo objeto, se debe pasar un puntero diferente. C++ resuelve esto definiendo una conversión implícita de cualquier objeto derivado a su objeto base. Es decir, en el siguiente código:

C* pc = something; 
pc->Afunc(); 

Este código es tratada internamente similar al siguiente (pseudo-código):

C* pc = something; 
Afunc(static_cast<A*>(pc)); 

Este reparto es, para-herencia simple, un no-operación (es decir, simplemente se puede eliminar) a través del truco mencionado en la cita: el objeto C y su objeto padre A se almacenan en la misma dirección física.Un objeto de tipo C que se almacena a una dirección x en la memoria se presenta físicamente a cabo de tal manera que su objeto primario de tipo A es también almacenado en la dirección x, y es seguido por todos los demás miembros que C pueden tener (pero en su caso no tiene miembros, y sizeof(C) == sizeof(A)).

+0

¿Podría volver a formular la última oración? – msiyer

+0

@msiyer He intentado agregar más información, con suerte esto es un poco más claro. –

+0

Esta es una gran explicación. Soy un graduado de Ingeniería Mecánica y, por lo tanto, no he tomado ningún curso de CS. Estoy, ahora, haciéndolo solo. Aprender todo eso es necesario para tener una base sólida en el diseño y construcción de compiladores. Con respuestas como estas, uno realmente no puede perderse mucho la educación formal de CS. Gracias Konrad. – msiyer

Cuestiones relacionadas