Inizializzazione dei membri durante l'utilizzo del costruttore delegato


96

Ho iniziato a provare lo standard C ++ 11 e ho trovato questa domanda che descrive come chiamare il tuo ctor da un altro ctor nella stessa classe per evitare di avere un metodo init o simili. Ora sto provando la stessa cosa con un codice simile a questo:

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

Ma questo mi sta dando l'errore: In constructor ‘config::Tokenizer::Tokenizer(std::stringstream*)’: /path/Tokenizer.cpp:14:20: error: mem-initializer for ‘config::Tokenizer::lines’ follows constructor delegationho provato a spostare la parte Tokenizer () prima e l'ultima nell'elenco, ma non è stato d'aiuto.

Qual è il motivo dietro questo e come dovrei risolverlo? Ho provato a spostare il lines(lines)to the body con this->lines = lines;invece e funziona bene. Ma mi piacerebbe davvero poter usare l'elenco degli inizializzatori.

Risposte:


118

Quando si delega l'inizializzazione del membro a un altro costruttore, si presume che l'altro costruttore inizializzi completamente l'oggetto , inclusi tutti i membri (cioè incluso il linesmembro nel tuo esempio). Non è quindi possibile inizializzare di nuovo nessuno dei membri.

La citazione rilevante dallo Standard è (enfasi mia):

(§12.6.2 / 6) Un mem-initializer-list può delegare a un altro costruttore della classe del costruttore usando qualsiasi class-o-decltype che denota la classe del costruttore stesso. Se un mem-inizializzatore-id designa la classe del costruttore, deve essere l'unico mem-inizializzatore ; il costruttore è un costruttore delegante e il costruttore selezionato da è il costruttore di destinazione. [...]

Puoi aggirare questo problema definendo la versione del costruttore che accetta prima gli argomenti :

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

e quindi definire il costruttore predefinito utilizzando la delega:

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

Come regola generale, è necessario specificare completamente la versione del costruttore che accetta il maggior numero di argomenti e quindi delegare dalle altre versioni (utilizzando i valori predefiniti desiderati come argomenti nella delega).


2
All'inizio sembra controintuitivo, ma in realtà aiuta davvero!
Korchkidu
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.