Объявление объекта перед его инициализацией в С++
Можно ли объявить переменную в С++ без ее создания? Я хочу сделать что-то вроде этого:
Animal a;
if( happyDay() )
a( "puppies" ); //constructor call
else
a( "toads" );
В принципе, я просто хочу объявить внешнюю часть условного выражения, чтобы получить правильную область.
Есть ли способ сделать это без использования указателей и выделения a
в кучу? Может быть, что-то умное со ссылками?
Ответы
Ответ 1
Вы не можете сделать это непосредственно в С++, поскольку объект создается, когда вы определяете его с помощью конструктора по умолчанию.
Однако вы можете запустить параметризованный конструктор, чтобы начать с:
Animal a(getAppropriateString());
Или вы можете использовать что-то вроде ?: operator
для определения правильной строки.
(Обновление: @Greg дал синтаксис для этого. См. Этот ответ)
Ответ 2
Вы не можете объявить переменную без вызова конструктора. Однако в вашем примере вы можете сделать следующее:
Animal a(happyDay() ? "puppies" : "toads");
Ответ 3
Здесь вы не можете использовать ссылки, так как, как только вы выйдете из области действия, ссылка будет указывать на объект, который будет удален.
Действительно, у вас есть два варианта:
1- Перейдите с указателями:
Animal* a;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
// ...
delete a;
2- Добавьте метод 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" );
Я бы лично пошел с вариантом 2.
Ответ 4
Я предпочитаю ответ Грега, но вы также можете это сделать:
char *AnimalType;
if( happyDay() )
AnimalType = "puppies";
else
AnimalType = "toads";
Animal a(AnimalType);
Я предлагаю это, потому что я работал там, где условный оператор был запрещен. (Вздох!) Кроме того, это можно легко расширить за пределы двух альтернатив.
Ответ 5
Если вы хотите избежать сбора мусора - вы можете использовать интеллектуальный указатель.
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 deleted.
Если вы все еще хотите использовать. синтаксис вместо → , вы можете сделать это после кода выше:
Animal& a = *p_a;
// do stuff with a. whatever
Ответ 6
В дополнение к ответу Грега Хьюглилла есть еще несколько вариантов:
Извлеките основную часть кода в функцию:
void body(Animal & a) {
...
}
if( happyDay() ) {
Animal a("puppies");
body( a );
} else {
Animal a("toad");
body( a );
}
(Ab) Использовать новое размещение:
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
Ответ 7
Лучшая работа - использовать указатель.
Animal a*;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
Ответ 8
Да, вы можете сделать следующее:
Animal a;
if( happyDay() )
a = Animal( "puppies" );
else
a = Animal( "toads" );
Это вызовет конструкторы должным образом.
EDIT: Забыл одну вещь...
При объявлении a вам придется вызывать конструктор еще, будь то конструктор, который ничего не делает или все еще инициализирует значения. Поэтому этот метод создает два объекта: один при инициализации и один внутри оператора if.
Лучше всего было бы создать функцию init() для класса, например:
Animal a;
if( happyDay() )
a.init( "puppies" );
else
a.init( "toads" );
Этот способ был бы более эффективным.