Déclarer un objet avant de l'initialiser en c ++
-
03-07-2019 - |
Question
Est-il possible de déclarer une variable en c ++ sans l'instancier? Je veux faire quelque chose comme ça:
Animal a;
if( happyDay() )
a( "puppies" ); //constructor call
else
a( "toads" );
En gros, je veux simplement déclarer un élément extérieur au conditionnel afin d'obtenir la bonne portée.
Y a-t-il un moyen de le faire sans utiliser de pointeurs ni allouer à
sur le tas? Peut-être que quelque chose d'intelligent avec des références?
La solution
Vous ne pouvez pas le faire directement en C ++ car l'objet est construit lorsque vous le définissez avec le constructeur par défaut.
Vous pouvez toutefois exécuter un constructeur paramétré pour commencer:
Animal a(getAppropriateString());
Vous pouvez également utiliser quelque chose comme l'opérateur ?:
pour déterminer la chaîne correcte.
(Mise à jour: @Greg a donné la syntaxe. Voir la réponse.)
Autres conseils
Vous ne pouvez pas déclarer une variable sans appeler un constructeur. Cependant, dans votre exemple, vous pouvez effectuer les opérations suivantes:
Animal a(happyDay() ? "puppies" : "toads");
Vous ne pouvez pas utiliser de références ici, car dès que vous sortiriez de la portée, la référence pointerait vers un objet qui serait supprimé.
Vraiment, vous avez deux choix ici:
1- Allez avec des pointeurs:
Animal* a;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
// ...
delete a;
2- Ajouter une méthode Init à 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" );
J'irais personnellement avec l'option 2.
Je préfère la réponse de Greg, mais vous pouvez également le faire:
char *AnimalType;
if( happyDay() )
AnimalType = "puppies";
else
AnimalType = "toads";
Animal a(AnimalType);
Je suggère cela parce que j'ai travaillé dans des endroits où l'opérateur conditionnel était interdit. (Soupir!) En outre, cela peut être étendu très facilement au-delà de deux alternatives.
Si vous souhaitez éviter la récupération de place, vous pouvez utiliser un pointeur intelligent.
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.
Si vous souhaitez toujours utiliser le. syntaxe au lieu de - > ;, vous pouvez le faire après le code ci-dessus:
Animal& a = *p_a;
// do stuff with a. whatever
Outre la réponse de Greg Hewgill, il existe quelques autres options:
Soulevez le corps du code dans une fonction:
void body(Animal & a) {
...
}
if( happyDay() ) {
Animal a("puppies");
body( a );
} else {
Animal a("toad");
body( a );
}
(Ab) Utiliser le placement nouveau:
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 meilleure solution consiste à utiliser un pointeur.
Animal a*;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
Oui, vous pouvez procéder comme suit:
Animal a;
if( happyDay() )
a = Animal( "puppies" );
else
a = Animal( "toads" );
Cela appellera les constructeurs correctement.
EDIT: Oublié une chose ... Lorsque vous déclarez un, vous devez toujours appeler un constructeur, qu’il s’agisse d’un constructeur qui ne fait rien ou qui initialise toujours les valeurs. Cette méthode crée donc deux objets, l'un à l'initialisation et l'autre à l'intérieur de l'instruction if.
Une meilleure solution consiste à créer une fonction init () de la classe, telle que:
Animal a;
if( happyDay() )
a.init( "puppies" );
else
a.init( "toads" );
Cette méthode serait plus efficace.