Pregunta

¿Es posible declarar una variable en c ++ sin crear una instancia? Quiero hacer algo como esto:

Animal a;
if( happyDay() ) 
    a( "puppies" ); //constructor call
else
    a( "toads" );

Básicamente, solo quiero declarar un fuera del condicional para que tenga el alcance correcto.

¿Hay alguna forma de hacer esto sin usar punteros y asignando a en el montón? Tal vez algo inteligente con referencias?

¿Fue útil?

Solución

No puede hacer esto directamente en C ++ ya que el objeto se construye cuando lo define con el constructor predeterminado.

Sin embargo, puede ejecutar un constructor parametrizado para comenzar con:

Animal a(getAppropriateString());

O, de hecho, podrías usar algo como el ?: operator para determinar la cadena correcta. (Actualización: @Greg dio la sintaxis para esto. Mira esa respuesta)

Otros consejos

No puede declarar una variable sin llamar a un constructor. Sin embargo, en su ejemplo, podría hacer lo siguiente:

Animal a(happyDay() ? "puppies" : "toads");

No puede usar referencias aquí, ya que tan pronto como salga del ámbito, la referencia apuntará a un objeto que se eliminará.

Realmente, tienes dos opciones aquí:

1- Ir con punteros:

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

// ...
delete a;

2- Agrega un método 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" );

Yo personalmente iría con la opción 2.

Prefiero la respuesta de Greg, pero también puedes hacer esto:

char *AnimalType;
if( happyDay() ) 
    AnimalType = "puppies";
else
    AnimalType = "toads";
Animal a(AnimalType);

Sugiero esto porque he trabajado en lugares donde el operador condicional estaba prohibido. (¡Suspiro!) Además, esto se puede expandir más allá de dos alternativas muy fácilmente.

Si desea evitar la recolección de basura, puede usar un puntero inteligente.

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 todavía quieres usar el. sintaxis en lugar de - > ;, puede hacer esto después del código anterior:

Animal& a = *p_a;

// do stuff with a. whatever

Además de la respuesta de Greg Hewgill, hay algunas otras opciones:

Levante el cuerpo principal del código en una función:

void body(Animal & a) {
    ...
}

if( happyDay() ) {
  Animal a("puppies");
  body( a );
} else {
  Animal a("toad");
  body( a );
}

(Ab) Usar ubicación nueva:

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

Lo mejor es usar el puntero.

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

Sí, puedes hacer lo siguiente:

Animal a;
if( happyDay() )
    a = Animal( "puppies" );
else
    a = Animal( "toads" );

Eso llamará a los constructores correctamente.

EDITAR: Olvidé una cosa ... Al declarar un, tendrás que llamar a un constructor todavía, ya sea un constructor que no hace nada, o aún inicializa los valores a lo que sea. Por lo tanto, este método crea dos objetos, uno en la inicialización y el otro dentro de la declaración if.

Una mejor manera sería crear una función init () de la clase, como:

Animal a;
if( happyDay() )
    a.init( "puppies" );
else
    a.init( "toads" );

De esta manera sería más eficiente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top