没有默认构造函数的成员对象的初始化列表
Posted
技术标签:
【中文标题】没有默认构造函数的成员对象的初始化列表【英文标题】:Initialisation list for an member object without default constructor 【发布时间】:2014-03-25 18:39:41 【问题描述】:我读到了在类中初始化的引用和对象。但是,除了提示之外,我找不到对以下问题的明确陈述:
如果没有默认构造函数(没有Object()
),我可以在初始化列表中初始化成员对象obj1
吗?
class Sample
private:
Object1 obj1(arguments);
public:
Sample(Object1 o1) : obj1( o1(arguments) )
;
问题出现了,因为如果有与此How can I initialize C++ object member variables in the constructor? 相关的问题。代码也是从那里获取的。感谢您的努力。
丹尼尔
编辑:
由于答案表明它有效,因此测试返回了一个错误(这正是我问这个问题的原因):
../src/Timestep.h:45:12: error: field ‘myFEMSolver’ has incomplete type FEMSolver myFEMSolver;
代码:
class Timestep
public:
Timestep();
private:
FEMSolver myFEMSolver;
Timestep::Timestep() : myFEMSolver(*this)
//do some stuff
FEMSolver::FEMSolver(const Timestep& theTimestep) : myTimestep(theTimestep)
//do some stuff
main()
Timestep myTimestep();
【问题讨论】:
该代码不会产生该错误。即,当FEMSolver
类本身被声明但在 TimeStep
被定义时未定义时,您会收到该错误。 FEMSolver
必须首先完全定义。这与初始化列表无关。 meta.stackexchange.com/questions/66377/what-is-the-xy-problem
其实不是XY问题。最初的问题对于意识到我打算做的事情确实有效很重要。但你对宣言的看法是对的。我切换了标题,现在它可以工作了。非常感谢。
X 是“产生这种不完整类型错误的原因”。 Y 是“如果没有默认构造函数,我可以在初始化列表中初始化一个成员对象吗”这是非常一个 X/Y 问题。
【参考方案1】:
如果没有默认构造函数(没有
Object()
),我可以在初始化列表中初始化成员对象obj1
吗?
是的。事实上,您必须这样做。
class Sample
private:
Object1 obj1;
public:
Sample() : obj1( /* ctor args */ )
;
如果您将另一个 Object1
传递给您的 Sample
构造函数,并将其传递给 Object1
的复制构造函数,那么您可能希望通过引用传递它:
Sample(const Object1& o) : obj1(o)
如果Object1
没有无参数构造函数,并且您没有在初始化列表中初始化obj1
,则会出现编译错误。
【讨论】:
【参考方案2】:如下更改你的类声明:
class Sample
private:
Object1 obj1;
public:
Sample(const Object1& o1) : obj1(o1)
;
要调用Sample
构造函数,请使用:
Sample s(Object1(arguments));
这要求您的Object1
是一个所谓的nice 类(提供复制构造函数和赋值运算符)。
对于任何其他情况,您需要使用 Object1
的引用或指针作为 Sample
类中的成员。
另一种(更简单)的方法是传递参数:
class Sample
private:
Object1 obj1;
public:
Sample(Args& arguments) : obj1(arguments)
;
【讨论】:
【参考方案3】:看来您要么想在列表初始化器中提供现有的Object1
,要么在嵌套的列表初始化器中创建Object1
,除非Object1
的构造函数是显式的。所以假设我们有
struct Object1
Object1(int, int) ;
;
那么在Sample
中通过复制、移动或它自己的参数来初始化Object1
的最通用方法是:
class Sample
private:
Object1 obj1;
public:
Sample(Object1&& o1) : obj1(std::move(o1))
Sample(const Object1& o1) : obj1(o1)
template<
typename... A,
typename = typename std::enable_if<std::is_constructible<Object1, A...>>
>
Sample(A&&... a) : obj1(std::forward<A>(a)...)
;
这允许我们使用多种Sample
构造:
int main ()
Object1 o11, 2;
const Object1& o2o1;
Sample s1Object11, 2;
Sample s21, 2;
Sample s31, 2;
Sample s4o1;
Sample s5o2;
如果Object1
的构造函数是explicit
,那么s2
是不允许的。根据您想要支持的内容,您当然可以通过多种方式简化Sample
。
【讨论】:
以上是关于没有默认构造函数的成员对象的初始化列表的主要内容,如果未能解决你的问题,请参考以下文章
为什么 没有缺省构造函数的类类型成员 必需要在初始化列表 里初始化 ?
为什么 没有缺省构造函数的类类型成员 必需要在初始化列表 里初始化 ?