私は次のようなものに要約されるC++コードを持っています:
class Foo{
bool bar;
bool baz;
Foo(const void*);
};
Foo::Foo(const void* ptr){
const struct my_struct* s = complex_method(ptr);
bar = calculate_bar(s);
baz = calculate_baz(s);
}
意味的には、barおよびbazメンバー変数は、初期化後に変更されるべきではないため、constである必要があります。ただし、そうするためには、割り当てるのではなく、初期化リストで初期化する必要があるようです。明確にするために、私は理解していますなぜ私はこれをする必要があります。問題は、次の望ましくないことのいずれかを実行せずに、コードを初期化リストに変換する方法を見つけることができないように思われることです。
complex_method
を2回呼び出します(パフォーマンスに悪影響があります)これらの望ましくない状況を回避しながら変数をconstにする方法はありますか?
C++ 11コンパイラを購入できる場合は、 コンストラクタの委任 を検討してください。
class Foo
{
// ...
bool const bar;
bool const baz;
Foo(void const*);
// ...
Foo(my_struct const* s); // Possibly private
};
Foo::Foo(void const* ptr)
: Foo{complex_method(ptr)}
{
}
// ...
Foo::Foo(my_struct const* s)
: bar{calculate_bar(s)}
, baz{calculate_baz(s)}
{
}
一般的なアドバイスとして、データメンバーをconst
として宣言する場合は注意が必要です。これにより、クラスでコピー代入とムーブ代入が不可能になるためです。クラスが値セマンティクスで使用されることになっている場合、それらの操作が望ましいものになります。そうでない場合は、このメモを無視してかまいません。
他の回答で説明されているように、1つのオプションはC++ 11委任コンストラクターです。 C++ 03互換のメソッドは、サブオブジェクトを使用することです。
class Foo{
struct subobject {
const bool bar;
const bool baz;
subobject(const struct my_struct* s)
: bar(calculate_bar(s))
, baz(calculate_baz(s))
{}
} subobject;
Foo(const void*);
};
Foo::Foo(const void* ptr)
: subobject(complex_method(ptr))
{}
bar
とbaz
constを作成するか、subobject
constを作成するか、またはその両方を行うことができます。
subobject
constのみを作成する場合は、complex_method
を計算し、bar
のコンストラクター内でbaz
とsubobject
に割り当てることができます。
class Foo{
const struct subobject {
bool bar;
bool baz;
subobject(const void*);
} subobject;
Foo(const void*);
};
Foo::Foo(const void* ptr)
: subobject(ptr)
{}
Foo::subobject::subobject(const void* ptr){
const struct my_struct* s = complex_method(ptr);
bar = calculate_bar(s);
baz = calculate_baz(s);
}
reasonコンストラクター本体内のconst
メンバーを変更できないのは、一貫性を保つために、コンストラクター本体が他のメンバー関数本体と同じように扱われるためです。コードをコンストラクターからメンバー関数に移動してリファクタリングすることができ、ファクタリングされたメンバー関数は特別な処理を必要としないことに注意してください。
C++ 11ではデリゲートコンストラクターを使用できます。
class Foo{
public:
Foo(const void* ptr) : Foo(complex_method(ptr)) {}
private:
Foo(const my_struct* s) : bar(calculate_bar(s)), baz(calculate_baz(s)) {}
private:
const bool bar;
const bool baz;
};
Newfangled委任コンストラクターを使用したくない場合(私はまだそれらについて知らないコンパイラーバージョンを処理する必要があります)、クラスのレイアウトを変更したくない場合は、解決策を選ぶことができますこれは、コンストラクターを_const void *
_引数に置き換え、Foo
を返す静的メンバー関数を使用しますが、_complex_method
_からの出力を引数として受け取るプライベートコンストラクターを持ちます(後者は、コンストラクターの委任例によく似ています)。 )。次に、静的メンバー関数は、_complex_method
_を含む必要な予備計算を実行し、return Foo(s);
で終了します。これには、クラスの呼び出し(return
ステートメント内)がおそらく省略できる場合でも、クラスにアクセス可能なコピーコンストラクターが必要です。