如何正确初始化非默认构造类成员?

问题描述:

假设我定义了一个类Foo,它没有实现默认的构造函数。 另外,我有一个类Bar,它“拥有”的Foo一个实例:如何正确初始化非默认构造类成员?

class Foo() { 
    private: 
    int m_member; 
    public: 
    Foo(int value) : m_member(value) { } 
}; 

class Bar() { 
    private: 
    Foo m_foo; 
    public: 
    Bar(/* ... */) { 
     int something; 
     /* lots of code to determine 'something' */ 
     /* should initialize m_foo to 'Foo(something)' here */ 
    } 
}; 

如图所示将不会运行的代码,因为Bar试图调用的Foo默认构造函数。

现在我想要做的是让Bar的构造函数首先确定something,然后将结果传递给Foo的构造函数。

解决此问题的一种方法是让Bar仅拥有指向Foo的引用/指针,并在确定m_something后对其进行初始化。但是,我想避免这样做,以明确m_foo的使用期限完全取决于拥有班级的生命周期。

另一种方法是在Foo中实现默认构造函数,并稍后设置值,这也是我也想避免的,因为Foo的任何实例都应该具有有效的成员值(任何时候)。

实现此目的的正确方法是什么?我坚持在这里参考/指针?

最好的想法是创建帮助函数,它将计算出一些内容,然后在构造函数初始化列表中初始化m_foo

class Bar { 
    private: 
    Foo m_foo; 
    public: 
    Bar(/* ... */) : m_foo(calculate_something()) { 
    } 
private: 
    static int calculate_something() 
    { 
     int something = 0; 
     // lot of code to calculate something 
     return something; 
    } 
}; 
+0

感谢您的回答。我也考虑过这样做,但是在这种情况下,我必须将'Bar'的大部分初始化操作移到帮助函数中,因为'something'依赖于此。 – madmax1

+1

@ madmax1不好。然后,只需要独立计算一些东西,或者使用你的一个想法(指针或默认的可构造的'Foo')。 – ForEveR

这是否复杂的初始化代码实际上属于Bar?考虑让一个分开类来完成初始化可能是一件好事。像

class Bar { 
    public: 
    Bar(int param, Foo foo): m_foo(foo) { 
     // do just some very simple calculations, or use only constructor initialization list 
    } 
    ... 
} 

class BarBuilder { 
    public: 
    BarBuilder(/*...*/) { 
     // do all calculations, boiling down to a few parameters for Bar and Foo 
     Foo foo(fooParameter); 
     m_result = new Bar(barParameter, foo); // give Foo here explicitly 
    } 
    Bar getResult() { return *m_result; } 
    private: 
    Bar* m_result; // or better use unique_ptr 
} 

这样的东西也开辟了道路,可能是在情况下很有用,例如,你并不总是需要所有的复杂计算全Builder模式。

这里假定所有的类都是可复制构建的,但是你可以或多或少的轻松修改它以支持你所需要的东西。