【问题标题】:Can't initialize field outside initializer list无法初始化初始值设定项列表之外的字段
【发布时间】:2017-07-14 01:57:42
【问题描述】:

我在一些看起来很容易的事情上遇到了麻烦,所以我一定忽略了一些事情。

我需要构造一个类,该类的字段也是类(非 POD)。该字段的类有一个默认构造函数和一个“真实”构造函数。问题是我真的无法在初始化列表中构造字段,因为实际上构造函数有一个参数,它是一个需要有点复杂的 for 循环来填充的向量。

这是重现问题的最小示例。

ConstructorsTest.h:

class SomeProperty {
public:
    SomeProperty(int param1); //Ordinary constructor.
    SomeProperty();           //Default constructor.
    int param1;
};

class ConstructorsTest {
    ConstructorsTest();
    SomeProperty the_property;
};

ConstructorsTest.cpp:

#include "ConstructorsTest.h"

ConstructorsTest::ConstructorsTest() {
    the_property(4);
}

SomeProperty::SomeProperty(int param1) : param1(param1) {}
SomeProperty::SomeProperty() : param1(0) {} //Default constructor, doesn't matter.

但这会产生编译错误:

ConstructorsTest.cpp: In constructor 'ConstructorsTest::ConstructorsTest()':
ConstructorsTest.cpp:4:19: error: no match for call to '(SomeProperty) (int)'
    the_property(4);
                  ^

它并没有像通常那样提供有关本来可以使用哪些功能的建议。

在上面的例子中,我只是在初始化列表中初始化the_property,但实际上4实际上是一个需要先生成的复杂向量,所以我真的不能。将the_property(4) 移动到初始化列表会导致编译成功。

其他类似的线程提到对象必须有default constructor,或者it can't be const。这两个要求似乎都已满足。

【问题讨论】:

    标签: c++ c++11 constructor initialization initializer-list


    【解决方案1】:

    你不能在构造函数体内初始化数据成员。 (the_property(4); 只是试图调用 the_property 作为仿函数。)您只能像这样分配它们:

    ConstructorsTest::ConstructorsTest() {
        the_property = ...;
    }
    

    但实际上4实际上是一个需要首先生成的复杂向量

    您可以添加一个生成必要数据的成员函数,并使用它来初始化member initializer list中的数据成员。例如

    class ConstructorsTest {
        ...
        static int generateData();
    };
    
    int ConstructorsTest::generateData() {
        return ...;
    }
    
    ConstructorsTest::ConstructorsTest() : the_property(generateData()) {
    }
    

    【讨论】:

    • 啊,所以诀窍是用= 实际分配它们。我知道这很简单!
    • @Ghostkeeper 注意赋值方式会默认构造数据成员,然后在构造函数体中赋值,它可能比使用成员初始化器列表效率低,后者将直接构造数据成员(没有分配)。
    【解决方案2】:

    你不能初始化一个变量两次1当你的构造函数启动时,所有成员子对象将被构造。如果你没有在构造函数中提供成员初始化器,或者在类定义中没有提供默认成员初始化器,那么它将执行默认初始化。无论采取何种形式,都无法再次构建。

    复杂的多语句初始化最好通过 lambda 函数完成:

    ConstructorsTest::ConstructorsTest()
      : the_property( []{ /* Do Complex Initialization */}() )
    {
    }
    

    1:嗯……你可以,但不是那样。而且你真的不应该处理这么简单的情况。

    【讨论】:

      猜你喜欢
      • 2012-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-16
      • 2012-12-25
      • 2010-10-23
      • 2021-12-19
      • 1970-01-01
      相关资源
      最近更新 更多