Dichiarare un oggetto prima di inizializzarlo in c ++
-
03-07-2019 - |
Domanda
È possibile dichiarare una variabile in c ++ senza istanziarla? Voglio fare qualcosa del genere:
Animal a;
if( happyDay() )
a( "puppies" ); //constructor call
else
a( "toads" );
Fondamentalmente, voglio solo dichiarare un esterno al condizionale in modo che ottenga lo scopo giusto.
Esiste un modo per farlo senza usare i puntatori e allocare a
sull'heap? Forse qualcosa di intelligente con riferimenti?
Soluzione
Non puoi farlo direttamente in C ++ poiché l'oggetto viene costruito quando lo definisci con il costruttore predefinito.
Tuttavia, è possibile eseguire un costruttore con parametri per iniziare:
Animal a(getAppropriateString());
Oppure potresti effettivamente usare qualcosa come ?: operator
per determinare la stringa corretta.
(Aggiornamento: @Greg ha fornito la sintassi per questo. Vedi quella risposta)
Altri suggerimenti
Non puoi dichiarare una variabile senza chiamare un costruttore. Tuttavia, nel tuo esempio potresti fare quanto segue:
Animal a(happyDay() ? "puppies" : "toads");
Non è possibile utilizzare i riferimenti qui, poiché non appena si esce dall'ambito, il riferimento punta a un oggetto che verrà eliminato.
Davvero, hai due scelte qui:
1- Vai con i puntatori:
Animal* a;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
// ...
delete a;
2- Aggiungi un metodo Init a Animal
:
class Animal
{
public:
Animal(){}
void Init( const std::string& type )
{
m_type = type;
}
private:
std:string m_type;
};
Animal a;
if( happyDay() )
a.Init( "puppies" );
else
a.Init( "toads" );
Vado personalmente con l'opzione 2.
Preferisco la risposta di Greg, ma potresti anche farlo:
char *AnimalType;
if( happyDay() )
AnimalType = "puppies";
else
AnimalType = "toads";
Animal a(AnimalType);
Lo suggerisco perché ho lavorato in luoghi in cui era vietato l'operatore condizionale. (Sospiro!) Inoltre, questo può essere ampliato molto facilmente oltre due alternative.
Se vuoi evitare la garbage collection, puoi usare un puntatore intelligente.
auto_ptr<Animal> p_a;
if ( happyDay() )
p_a.reset(new Animal( "puppies" ) );
else
p_a.reset(new Animal( "toads" ) );
// do stuff with p_a-> whatever. When p_a goes out of scope, it's deleted.
Se vuoi ancora usare il. sintassi invece di - > ;, puoi farlo dopo il codice sopra:
Animal& a = *p_a;
// do stuff with a. whatever
Oltre alla risposta di Greg Hewgill, ci sono alcune altre opzioni:
Estrai il corpo principale del codice in una funzione:
void body(Animal & a) {
...
}
if( happyDay() ) {
Animal a("puppies");
body( a );
} else {
Animal a("toad");
body( a );
}
(Ab) Usa posizionamento nuovo:
struct AnimalDtor {
void *m_a;
AnimalDtor(void *a) : m_a(a) {}
~AnimalDtor() { static_cast<Animal*>(m_a)->~Animal(); }
};
char animal_buf[sizeof(Animal)]; // still stack allocated
if( happyDay() )
new (animal_buf) Animal("puppies");
else
new (animal_buf) Animal("toad");
AnimalDtor dtor(animal_buf); // make sure the dtor still gets called
Animal & a(*static_cast<Animal*>(static_cast<void*>(animal_buf));
... // carry on
La soluzione migliore è utilizzare il puntatore.
Animal a*;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
Sì, puoi fare quanto segue:
Animal a;
if( happyDay() )
a = Animal( "puppies" );
else
a = Animal( "toads" );
Questo chiamerà correttamente i costruttori.
EDIT: ho dimenticato una cosa ... Quando dichiari un, dovrai chiamare ancora un costruttore, che si tratti di un costruttore che non fa nulla o che inizializza comunque i valori a qualunque cosa. Questo metodo crea quindi due oggetti, uno all'inizializzazione e l'altro all'interno dell'istruzione if.
Un modo migliore sarebbe quello di creare una funzione init () della classe, come ad esempio:
Animal a;
if( happyDay() )
a.init( "puppies" );
else
a.init( "toads" );
In questo modo sarebbe più efficiente.