2009-01-14 16 views
27

¿Puedo pasar "esto" a una función como un puntero, desde dentro del constructor de la clase, y usarlo para apuntar a los miembros del objeto antes de que el constructor regrese?Pasando "esto" a una función desde dentro de un constructor?

¿Es seguro hacer esto, siempre y cuando los miembros accedidos se inicialicen correctamente antes de la llamada de función?

A modo de ejemplo:

#include <iostream> 

class Stuff 
{ 
public: 
    static void print_number(void *param) 
    { 
     std::cout << reinterpret_cast<Stuff*>(param)->number; 
    } 

    int number; 

    Stuff(int number_) 
     : number(number_) 
    { 
     print_number(this); 
    } 
}; 

void main() { 
    Stuff stuff(12345); 
}

pensé que esto no iba a funcionar, pero parece. ¿Este comportamiento estándar, o solo un comportamiento indefinido, sigue mi camino?

Respuesta

30

Cuando instancia un objeto en C++, el código en el constructor es lo último que se ejecuta. Todas las demás inicializaciones, incluida la inicialización de superclase, la ejecución del constructor de superclase y la asignación de memoria, suceden de antemano. El código en el constructor es realmente solo para realizar una inicialización adicional una vez que se construye el objeto. Por lo tanto, es perfectamente válido utilizar un puntero "this" en un constructor de clase y asumir que apunta a un objeto completamente construido.

Por supuesto, aún necesita tener cuidado con las variables miembro no inicializadas, si aún no las ha inicializado en su código de constructor.

+4

Half true. Piense dos veces antes de usar esto en un constructor, especialmente cuando algo podría derivar de la clase. En ese caso, usted trabaja con una clase parcialmente construida y la llamada virtual es, afaik, indefinida. Lo mismo es cierto para el "estado de clase" general: el constructor derivado aún puede modificarlo. – user52875

4

Puede encontrar una buena respuesta a este here (C++ FAQ).

Todos los miembros heredados y miembros de la clase de llamada tienen la garantía de haber sido construidos al inicio de la ejecución del código del constructor y, por lo tanto, pueden ser referenciados de manera segura dentro de este.

El problema principal es que no debe llamar a funciones virtuales en this. La mayoría de las veces que lo he probado termina llamando a la función de la clase base, pero creo que el estándar dice que el resultado no está definido.

+0

El enlace aparece o se rompe ... –

+0

No está definido para funciones virtuales puras (que aún no tienen una definición). –

-2

Andy, creo que te equivocas sobre la parte indefinida del estándar.

Cuando se encuentra en el constructor, "esto" es un puntero a un objeto cuyo tipo es clase base del objeto que está creando, lo que significa que las funciones virtuales implementadas parcialmente en la clase base serán llamado y no se seguirán los punteros en la tabla virtual.

Más información en la C++ Faq Lite ...

+0

Incorrecto: cuando ingresa Derived :: Derived, this-> ya apunta a un objeto derivado. Esto difiere de, por ejemplo, Java, donde esto. puede señalar el objeto MostDerived. En ninguno de los dos lenguajes esto-> señalará "a" la clase Base en el constructor de Derived.Además, con MI, ¿a qué base se referiría esto? – MSalters

0

Como nota lateral sobre el código presentado, yo en su lugar crear plantillas de la void*:

class Stuff 
{ 
public: 
    template <typename T> 
    static void print_number(const T& t) 
    { 
     std::cout << t.number; 
    } 

    int number; 

    Stuff(int number_) 
    : number(number_) 
    { 
     print_number(*this); 
    } 
}; 

A continuación, se obtendría un error de compilación si el tipo de t no tiene un miembro number.

Cuestiones relacionadas