web-dev-qa-db-fra.com

Déclarer un objet avant de l'initialiser en c ++

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" );

Fondamentalement, je veux simplement déclarer un extérieur du conditionnel afin qu'il obtienne la bonne portée.

Existe-t-il un moyen de le faire sans utiliser de pointeurs et allouer a sur le tas? Peut-être quelque chose d'intelligent avec des références?

45
Quantum7

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 cependant exécuter un constructeur paramétré pour commencer:

Animal a(getAppropriateString());

Vous pouvez également utiliser quelque chose comme ?: operator pour déterminer la chaîne correcte. (Mise à jour: @Greg a donné la syntaxe pour cela. Voir cette réponse)

33
Uri

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");
41
Greg Hewgill

Vous ne pouvez pas utiliser de références ici, car dès que vous seriez hors de 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- Ajoutez 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" );

Je choisirais personnellement l'option 2.

21
joce

Je préfère la réponse de Greg, mais vous pouvez également faire ceci:

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!) De plus, cela peut être étendu au-delà de deux alternatives très facilement.

16
Steve Fallows

Si vous voulez éviter le ramasse-miettes, 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
7
paquetp

En plus de la réponse de Greg Hewgill, il existe quelques autres options:

Soulevez le corps principal 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
6
Logan Capaldo

La meilleure solution consiste à utiliser le pointeur.

Animal a*;
if( happyDay() ) 
    a = new Animal( "puppies" ); //constructor call
else
    a = new Animal( "toads" );
1
rkadeFR