可能性のある複製:
初期化メソッドの使用を避ける
クラスの重要な初期化をいつ行うかを決定したいと思います。初期化を行うために、コンストラクタと他のメソッドの2回を確認します。それぞれを使用するタイミングを知りたい。
コンストラクターは初期化を行います
MyClass::MyClass(Data const& data) : m_data()
{
// does non-trivial initialization here
}
MyClass::~MyClass()
{
// cleans up here
}
初期化を初期化メソッドに延期する
MyClass::MyClass() : m_data()
{}
MyClass::Initialize(Data const& data)
{
// does non-trivial initialization here
}
MyClass::~MyClass()
{
// cleans up here
}
正当な理由がない限り、常にコンストラクタを使用してください。 「C++ウェイ」(tm)です。
考慮すべき点について:
コンストラクターは、独立したinit()関数の外側にコードを置くのと同じくらい効率的です。
コンストラクターは他の開発者にとって使いやすい傾向があります。ソースやドキュメントを確認しなければ、new YourClass(stuff)
が機能することを期待します。後でyourClass->init(stuff)
を呼び出さなければならないことはコンパイラーによって強制されず、簡単に作成できます。
数値2のとおり、初期化の順序などの点で、コンストラクターに関する多くの警告がコンパイラーによって具体化されます。コンストラクターの外に物事を移動すると、ホイールが、場合によっては四角形として再発明される危険に直面します。
理想的には、コンストラクタを使用するだけです。コンストラクターが使用できないオブジェクトを返す場合、これは通常悪いことです。
しかし、人々が指摘したように、オブジェクトを完全に初期化するために必要なデータが構築時に利用できない状況がよくあります。このような状況に対処するには、ビルダーパターンを使用します。
クラスFoo
があるとします。これには、重要な初期化が必要です。クラスFooBuilder
を作成します。これは、Foo
のオブジェクトを初期化するために必要なすべてのデータを格納するだけです。 FooBuilder
にはメンバー関数(別名メソッド)Foo *build()
またはFoo build()
があり、すべてのデータが収集されたときに呼び出すことができます。また、Fooのコンストラクターに渡す必要のあるさまざまな項目のセッターがあり、それらの一部にデフォルトを提供する場合があります。
これにより、initialize()
メンバー関数を必要とせずに「遅延初期化」の問題が解決されます。たとえば、Foo
オブジェクトの配列を作成してから初期化する必要がある場合は、代わりにFooBuilder
sの配列を作成します。次に、データが使用可能になったら、ビルダーで適切なセッターを呼び出します。最後に、すべてのデータがビルダーに安全に格納されたら、各ビルダーでbuild()
を呼び出して、Foo
の配列を作成します。
誰も触れなかったように思われる1つのオプションは、プライベートコンストラクターと静的なInitialize関数を使用してInitを構築する代わりです。実際、これは強力な手法です。理論的には、静的な初期化関数がコンテキストに基づいて異なるサブクラスを構築する可能性があるためです。
どちらかを選びます。他の人が述べたように、コンストラクターの後にInitialize呼び出しを続けるとエラーが発生しやすくなります。
オブジェクトの作成時にわからない/わからないパラメーターをオブジェクトに提供する必要がある場合は、Init()
を使用します。
クラスの機能を構築するのに時間がかかる場合も使用できます。ビデオファイルの再生の初期化には、ファイルの解析、ビデオコーデックのマッチングとロード、オーディオコーデックのマッチングとロード、リソースの取得が含まれます。この場合、作成を非同期ステップに分割して、ユーザーのアプリが応答性を維持し、操作をキャンセルできるようにすることもできます。