Passando & # 8220; questo & # 8221; a una funzione all'interno di un costruttore?
-
22-07-2019 - |
Domanda
Posso passare " questo " a una funzione come puntatore, all'interno del costruttore della classe, e utilizzarla per puntare ai membri dell'oggetto prima che il costruttore ritorni?
È sicuro farlo, purché i membri a cui si accede siano inizializzati correttamente prima della chiamata di funzione?
Ad esempio:
#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);
}
Pensavo che non avrebbe funzionato, ma sembra. Questo comportamento standard o semplicemente un comportamento indefinito sta andando per la mia strada?
Soluzione
Quando si crea un'istanza di un oggetto in C ++, il codice nel costruttore è l'ultima cosa eseguita. Tutte le altre inizializzazioni, inclusa l'inizializzazione della superclasse, l'esecuzione del costruttore della superclasse e l'allocazione della memoria avvengono in anticipo. Il codice nel costruttore è davvero solo per eseguire un'inizializzazione aggiuntiva una volta che l'oggetto è stato costruito. Quindi è perfettamente valido usare un "questo" puntatore nel costruttore di una classe e supponiamo che punti a un oggetto completamente costruito.
Ovviamente, devi ancora fare attenzione alle variabili membro non inizializzate, se non le hai già inizializzate nel tuo codice costruttore.
Altri suggerimenti
Puoi trovare una buona risposta a questo qui (FAQ C ++).
Si garantisce che tutti i membri ereditati e i membri della classe chiamante sono stati costruiti all'inizio dell'esecuzione del codice del costruttore e quindi possono essere referenziati in modo sicuro al suo interno.
Il gotcha principale è che non dovresti chiamare funzioni virtuali su this
. La maggior parte delle volte che ci ho provato finisce per chiamare la funzione della classe base, ma credo che lo standard affermi che il risultato non è definito.
Come nota a margine sul codice presentato, vorrei invece modellare il 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);
}
};
Quindi visualizzerai un errore di compilazione se il tipo di t
non ha un membro numero
.
Andy, penso che ti sbagli sulla parte indefinita dello standard.
Quando sei nel costruttore, " questo " è un puntatore a un oggetto il cui tipo è la classe base dell'oggetto che si sta creando, il che significa che le funzioni virtuali parzialmente implementate nella classe base verranno chiamate e i puntatori nella tabella virtuale vinceranno " essere seguito.
Ulteriori informazioni nel C ++ Faq Lite ...