使用委托构造函数进行成员初始化


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;代替将其移动到身体,并且效果很好。但是我真的很希望能够使用初始化列表。

Answers:


118

当您将成员初始化委托给另一个构造函数时,会假设另一个构造函数会完全初始化对象,包括所有成员(即lines,示例中的成员)。因此,您无法再次初始化任何成员。

该标准的相关引用是(强调我的):

(第12.6.2 / 6节)mem-initializer-list可以使用任何表示构造函数类本身的class-或-decltype委托给该构造函数类的另一个构造函数。如果mem-initializer-id指定了构造函数的类,则它将是唯一的mem-initializer;构造函数是委托的构造函数,而由选择的构造函数是目标构造函数。[...]

您可以通过定义首先采用参数的构造函数版本来解决此问题:

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

然后使用委托定义默认构造函数:

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

通常,您应该完全指定构造函数的版本,该版本使用最多数量的参数,然后从其他版本进行委派(在委派中使用所需的默认值作为参数)。


2
乍一看似乎违反直觉,但实际上确实有帮助!
Korchkidu 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.