C++ で初期化する前にオブジェクトを宣言する
-
03-07-2019 - |
質問
C++で変数をインスタンス化せずに宣言することは可能ですか?次のようなことをしたいです:
Animal a;
if( happyDay() )
a( "puppies" ); //constructor call
else
a( "toads" );
基本的に、条件式の外側を宣言して、適切なスコープを取得したいだけです。
ポインタを使用せずにこれを行う方法はありますか a
山の上に?おそらく参照を使った何か賢いことがあるでしょうか?
解決
デフォルトのコンストラクタでオブジェクトを定義するとオブジェクトが構築されるため、C ++で直接これを行うことはできません。
ただし、パラメータ化されたコンストラクタを実行して、次のことを開始できます。
Animal a(getAppropriateString());
または実際に ?: operator
のようなものを使用して、正しい文字列を決定できます。
(更新:@Gregはこのための構文を提供しました。その答えを参照してください)
他のヒント
コンストラクターを呼び出さずに変数を宣言することはできません。ただし、この例では次のことができます。
Animal a(happyDay() ? "puppies" : "toads");
ここで参照を使用することはできません。スコープから出るとすぐに、参照は削除されるオブジェクトを指すからです。
本当に、ここには2つの選択肢があります:
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を使用します。
グレッグの答えが好きですが、これもできます:
char *AnimalType;
if( happyDay() )
AnimalType = "puppies";
else
AnimalType = "toads";
Animal a(AnimalType);
これは、条件演算子が禁止されている場所で作業したためです。 (ため息!)また、これは非常に簡単に2つの選択肢を超えて拡張できます。
ガベージ コレクションを避けたい場合は、スマート ポインターを使用できます。
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
グレッグヒューギルの答えに加えて、他にもいくつかのオプションがあります。
コードの本体を関数に持ち上げます:
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" );
はい、次のことができます:
Animal a;
if( happyDay() )
a = Animal( "puppies" );
else
a = Animal( "toads" );
それはコンストラクタを適切に呼び出します。
編集:1つのことを忘れました... aを宣言するとき、何もしないコンストラクタであるか、値を何にでも初期化するかどうかに関係なく、コンストラクタをまだ呼び出す必要があります。したがって、このメソッドは2つのオブジェクトを作成します。1つは初期化時に、もう1つはifステートメント内にあります。
より良い方法は、次のようなクラスのinit()関数を作成することです。
Animal a;
if( happyDay() )
a.init( "puppies" );
else
a.init( "toads" );
この方法はより効率的です。