委任コンストラクターの使用中のメンバーの初期化


96

私はC ++ 11標準を試し始めましたが、同じクラスの別のctorからctorを呼び出してinitメソッドなどを回避する方法を説明するこの質問を見つけました。今、私は次のようなコードで同じことを試しています:

hpp:

class Tokenizer
{
public:
  Tokenizer();
  Tokenizer(std::stringstream *lines);
  virtual ~Tokenizer() {};
private:
  std::stringstream *lines;
};

cpp:

Tokenizer::Tokenizer()
  : expected('=')
{
}

Tokenizer::Tokenizer(std::stringstream *lines)
  : Tokenizer(),
    lines(lines)
{
}

しかし、これは私にエラーを与えています: In constructor ‘config::Tokenizer::Tokenizer(std::stringstream*)’: /path/Tokenizer.cpp:14:20: error: mem-initializer for ‘config::Tokenizer::lines’ follows constructor delegationTokenizer()の部分をリストの最初と最後に移動しようとしましたが、それは役に立ちませんでした。

これの背後にある理由は何ですか、どうすれば修正できますか?代わりにをlines(lines)体に移動してみましたが、this->lines = lines;正常に動作します。しかし、私は本当に初期化リストを使用できるようにしたいと思います。

回答:


118

メンバーの初期化を別のコンストラクターに委任すると、他のコンストラクターがオブジェクトを初期化すると想定されます。 すべてのメンバーを含む(つまりlines、例のメンバーを含む)完全にれます。したがって、メンバーを再び初期化することはできません。

標準からの関連する引用は(私の強調)です:

(§12.6.2/ 6)mem-initializer-listは、コンストラクターのクラス自体を表すclass-or-decltypeを使用して、コンストラクターのクラスの別のコンストラクターに委任できます。mem-initializer-idがコンストラクターのクラスを指定している場合、それが唯一のmem-initializerになります。コンストラクターは委任コンストラクターであり、によって選択されたコンストラクターがターゲットコンストラクターです。[...]

最初に引数を取るコンストラクタのバージョンを定義することで、これを回避できます。

Tokenizer::Tokenizer(std::stringstream *lines)
  : lines(lines)
{
}

次に、委任を使用してデフォルトのコンストラクタを定義します。

Tokenizer::Tokenizer()
  : Tokenizer(nullptr)
{
}

原則として、引数の数が最も多いコンストラクターのバージョンを完全に指定し、他のバージョンから委任する必要があります(委任で引数として目的のデフォルト値を使用)。


2
最初は直感に反するように見えますが、実際には本当に役に立ちます!
Korchkidu 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.