Inisialisasi anggota saat menggunakan konstruktor yang didelegasikan

96

Saya sudah mulai mencoba standar C ++ 11 dan saya menemukan pertanyaan ini yang menjelaskan bagaimana memanggil ctor Anda dari ctor lain di kelas yang sama untuk menghindari metode init atau sejenisnya. Sekarang saya mencoba hal yang sama dengan kode yang terlihat seperti ini:

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)
{
}

Tetapi ini memberi saya kesalahan: In constructor ‘config::Tokenizer::Tokenizer(std::stringstream*)’: /path/Tokenizer.cpp:14:20: error: mem-initializer for ‘config::Tokenizer::lines’ follows constructor delegationSaya sudah mencoba memindahkan bagian Tokenizer () pertama dan terakhir dalam daftar tetapi itu tidak membantu.

Apa alasan di balik ini dan bagaimana cara memperbaikinya? Saya sudah mencoba memindahkan lines(lines)ke tubuh dengan this->lines = lines;sebagai gantinya dan itu berfungsi dengan baik. Tetapi saya benar-benar ingin bisa menggunakan daftar penginisialisasi.

lfxgroove.dll
sumber

Jawaban:

118

Ketika Anda mendelegasikan inisialisasi anggota ke konstruktor lain, ada asumsi bahwa konstruktor lain menginisialisasi objek sepenuhnya , termasuk semua anggota (mis.lines anggota dalam contoh Anda). Oleh karena itu, Anda tidak dapat menginisialisasi salah satu anggota lagi.

Kutipan relevan dari Standard adalah (penekanan dari saya):

(§12.6.2 / 6) Sebuah mem-penginisialisasi-daftar dapat mendelegasikan ke konstruktor lain dari kelas konstruktor menggunakan kelas-atau-deklarasi yang menunjukkan kelas konstruktor itu sendiri. Jika mem-initializer-id menunjuk kelas konstruktor, itu akan menjadi satu-satunya mem-initializer ; konstruktor adalah konstruktor delegasi, dan konstruktor dipilih oleh konstruktor target. [...]

Anda bisa menyiasatinya dengan menentukan versi konstruktor yang mengambil argumen terlebih dahulu :

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

dan kemudian tentukan konstruktor default menggunakan delegasi:

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

Sebagai aturan umum, Anda harus sepenuhnya menentukan versi konstruktor yang mengambil argumen paling banyak, lalu mendelegasikan dari versi lain (menggunakan nilai default yang diinginkan sebagai argumen dalam delegasi).

jogojapan
sumber
2
Tampaknya kontra-intuitif pada awalnya tetapi sebenarnya sangat membantu!
Korchkidu