web-dev-qa-db-ja.com

C ++-起動するコンストラクターまたは初期化メソッド

可能性のある複製:
初期化メソッドの使用を避ける

クラスの重要な初期化をいつ行うかを決定したいと思います。初期化を行うために、コンストラクタと他のメソッドの2回を確認します。それぞれを使用するタイミングを知りたい。

選択肢1:

コンストラクターは初期化を行います

MyClass::MyClass(Data const& data) : m_data()
{
    // does non-trivial initialization here
}

MyClass::~MyClass()
{
   // cleans up here
}

選択2:

初期化を初期化メソッドに延期する

MyClass::MyClass() : m_data()
{}

MyClass::Initialize(Data const& data)
{
    // does non-trivial initialization here
}

MyClass::~MyClass()
{
    // cleans up here
}

したがって、主観性を試して削除するために、いくつかの状況でどちらが良いかを理解したいと思います。

  1. リソースをカプセル化するクラス(ウィンドウ/フォント/何らかのハンドル)
  2. リソースを合成して何かを行うクラス(コントロール/ドメインオブジェクト)
  3. データ構造クラス(ツリー/リスト/など)
  4. [あなたが考えることができる他のものすべて]

分析するもの:

  1. パフォーマンス
  2. 他の開発者による使いやすさ
  3. バグのエラーが発生しやすい/機会
  4. [あなたが考えることができる他のものすべて]
22
Bob Fincheimer

正当な理由がない限り、常にコンストラクタを使用してください。 「C++ウェイ」(tm)です。

考慮すべき点について:

  1. コンストラクターは、独立したinit()関数の外側にコードを置くのと同じくらい効率的です。

  2. コンストラクターは他の開発者にとって使いやすい傾向があります。ソースやドキュメントを確認しなければ、new YourClass(stuff)が機能することを期待します。後でyourClass->init(stuff)を呼び出さなければならないことはコンパイラーによって強制されず、簡単に作成できます。

  3. 数値2のとおり、初期化の順序などの点で、コンストラクターに関する多くの警告がコンパイラーによって具体化されます。コンストラクターの外に物事を移動すると、ホイールが、場合によっては四角形として再発明される危険に直面します。

23
MrFox

理想的には、コンストラクタを使用するだけです。コンストラクターが使用できないオブジェクトを返す場合、これは通常悪いことです。

しかし、人々が指摘したように、オブジェクトを完全に初期化するために必要なデータが構築時に利用できない状況がよくあります。このような状況に対処するには、ビルダーパターンを使用します。

クラスFooがあるとします。これには、重要な初期化が必要です。クラスFooBuilderを作成します。これは、Fooのオブジェクトを初期化するために必要なすべてのデータを格納するだけです。 FooBuilderにはメンバー関数(別名メソッド)Foo *build()またはFoo build()があり、すべてのデータが収集されたときに呼び出すことができます。また、Fooのコンストラクターに渡す必要のあるさまざまな項目のセッターがあり、それらの一部にデフォルトを提供する場合があります。

これにより、initialize()メンバー関数を必要とせずに「遅延初期化」の問題が解決されます。たとえば、Fooオブジェクトの配列を作成してから初期化する必要がある場合は、代わりにFooBuildersの配列を作成します。次に、データが使用可能になったら、ビルダーで適切なセッターを呼び出します。最後に、すべてのデータがビルダーに安全に格納されたら、各ビルダーでbuild()を呼び出して、Fooの配列を作成します。

7
Dima

誰も触れなかったように思われる1つのオプションは、プライベートコンストラクターと静的なInitialize関数を使用してInitを構築する代わりです。実際、これは強力な手法です。理論的には、静的な初期化関数がコンテキストに基づいて異なるサブクラスを構築する可能性があるためです。

どちらかを選びます。他の人が述べたように、コンストラクターの後にInitialize呼び出しを続けるとエラーが発生しやすくなります。

2
Michael Brown

オブジェクトの作成時にわからない/わからないパラメーターをオブジェクトに提供する必要がある場合は、Init()を使用します。

クラスの機能を構築するのに時間がかかる場合も使用できます。ビデオファイルの再生の初期化には、ファイルの解析、ビデオコーデックのマッチングとロード、オーディオコーデックのマッチングとロード、リソースの取得が含まれます。この場合、作成を非​​同期ステップに分割して、ユーザーのアプリが応答性を維持し、操作をキャンセルできるようにすることもできます。

0
James