Ініціалізація члена при використанні делегованого конструктора


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 delegationя спробував перемістити частину Tokenizer () першою та останньою у списку, але це не допомогло.

У чому причина цього і як я можу це виправити? Я намагався перемістити lines(lines)тіло за допомогою, this->lines = lines;а це працює чудово. Але я дуже хотів би мати можливість використовувати список ініціалізатора.

Відповіді:


118

Коли ви делегуєте ініціалізацію члена іншому конструктору, існує припущення, що інший конструктор ініціалізує об'єкт повністю , включаючи всі члени (тобто включаючи linesчлена у вашому прикладі). Тому ви не можете знову ініціалізувати жодного з членів.

Відповідна цитата стандарту:

(§12.6.2 / 6) Список ініціалізаторів пам’яті може делегувати іншому конструктору класу конструктора, використовуючи будь-який клас або дельттип, який позначає сам клас конструктора. Якщо mem-inicijalizer-id позначає клас конструктора, він буде єдиним ініціалізатором mem ; конструктор - це делегуючий конструктор, а конструктор, обраний командою - це цільовий конструктор. [...]

Ви можете подолати це, визначивши версію конструктора, який спочатку бере аргументи :

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

а потім визначте конструктор за замовчуванням за допомогою делегування:

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

Як правило, ви повинні повністю вказати ту версію конструктора, яка приймає найбільшу кількість аргументів, а потім делегувати інші версії (використовуючи бажані значення за замовчуванням як аргументи в делегуванні).


2
Спочатку це здається контрінтуїтивним, але насправді допомагає!
Корчкіду
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.