是否可以在不实例化的情况下在 C++ 中声明一个变量?我想做这样的事情:
Animal a;
if( happyDay() )
a( "puppies" ); //constructor call
else
a( "toads" );
基本上,我只想在条件之外声明 a ,以便获得正确的范围。
有没有办法在不使用指针和a
在堆上分配的情况下做到这一点?也许有一些聪明的参考?
是否可以在不实例化的情况下在 C++ 中声明一个变量?我想做这样的事情:
Animal a;
if( happyDay() )
a( "puppies" ); //constructor call
else
a( "toads" );
基本上,我只想在条件之外声明 a ,以便获得正确的范围。
有没有办法在不使用指针和a
在堆上分配的情况下做到这一点?也许有一些聪明的参考?
不调用构造函数就不能声明变量。但是,在您的示例中,您可以执行以下操作:
Animal a(happyDay() ? "puppies" : "toads");
你不能在这里使用引用,因为一旦你离开范围,引用就会指向一个将被删除的对象。
真的,你有两个选择:
1-使用指针:
Animal* a;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
// ...
delete a;
或使用智能指针
#include <memory>
std::unique_ptr<Animal> a;
if( happyDay() )
a = std::make_unique<Animal>( "puppies" );
else
a = std::make_unique<Animal>( "toads" );
2-添加一个初始化方法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。
您不能直接在 C++ 中执行此操作,因为该对象是在您使用默认构造函数定义它时构造的。
但是,您可以运行参数化构造函数以开始:
Animal a(getAppropriateString());
或者您实际上可以使用类似的东西?: operator
来确定正确的字符串。(更新:@Greg 给出了这个语法。见那个答案)
我更喜欢格雷格的回答,但你也可以这样做:
char *AnimalType;
if( happyDay() )
AnimalType = "puppies";
else
AnimalType = "toads";
Animal a(AnimalType);
我建议这样做是因为我曾在禁止条件运算符的地方工作过。(叹气!)此外,这可以很容易地扩展到两个替代方案之外。
如果您想避免垃圾收集 - 您可以使用智能指针。
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.
如果您仍然想使用 . 语法而不是 ->,您可以在上面的代码之后执行此操作:
Animal& a = *p_a;
// do stuff with a. whatever
除了 Greg Hewgill 的回答之外,还有其他一些选择:
将代码主体提炼成一个函数:
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
最好的解决方法是使用指针。
Animal a*;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
从 c++17 开始,现在有一种无开销的方法可以做到这一点:std::optional
. 这种情况下的代码是:
#include <optional>
std::optional<Animal> a;
if(happyDay())
a.emplace("puppies");
else
a.emplace("toads");
您还可以使用 std::move:
class Ball {
private:
// This is initialized, but not as needed
sf::Sprite ball;
public:
Ball() {
texture.loadFromFile("ball.png");
// This is a local object, not the same as the class member.
sf::Sprite ball2(texture);
// move it
this->ball=std::move(ball2);
}
...
是的,您可以执行以下操作:
Animal a;
if( happyDay() )
a = Animal( "puppies" );
else
a = Animal( "toads" );
这将正确调用构造函数。
编辑:忘记一件事......在声明a时,您仍然必须调用构造函数,无论它是什么都不做的构造函数,还是仍然将值初始化为任何值。因此,此方法创建了两个对象,一个在初始化时创建,一个在 if 语句中。
更好的方法是创建类的 init() 函数,例如:
Animal a;
if( happyDay() )
a.init( "puppies" );
else
a.init( "toads" );
这种方式会更有效率。