【问题标题】:Constructor invocation order for member objects成员对象的构造函数调用顺序
【发布时间】:2022-01-23 10:35:32
【问题描述】:

我有一个名为 Tree 的类,它有一个 Leaf 类的成员对象。 Leaf 需要一个来自 Tree (height_) 的参数来构建它。我可以为此编写一个初始化方法。但是我们是否知道构造函数的调用顺序,以便在构造 Tree 类时满足构造成员对象的依赖关系? 换句话说,当成员对象的实例化存在依赖关系时,单独的初始化方法(针对成员对象)是唯一的方法吗? 下面是一个最小的代码,我在 Leaf 的构造函数的参数中放了一个问号来表示我的问题:

class Tree {
    private:
    float height_;
    Leaf leaf_(?);
    public:
    explicit Leaf(const std::istream& input);
};
void Tree::Tree(const std::istream& input){
    // read height_ from input
    ...
}
class Leaf {
    private:
    float height_fraction_;
    public:
    // height is required for construction of Leaf class
    Leaf(const float& height); 
};
void Leaf::Leaf(const float& height)
{
    height_fraction_ = 0.5*height; 
}

【问题讨论】:

  • 您的教科书、教程或课堂笔记对构造函数初始化列表有什么看法?
  • 这能回答你的问题吗? Order of member constructor and destructor calls
  • @RetiredNinja 问题是相关的,但在我的情况下存在依赖关系。我的问题也是,如果单独的初始化方法是唯一的选择。我已经编辑了问题以明确这一点。
  • 一种思想流派是,您不应该在构造函数中做很多工作,因此将流传递给它进行解析有点代码味道,对您来说是个问题,因为您似乎要需要解析的结果来初始化成员,您可能会考虑使用工厂,以便您可以解析构造对象所需的数据,然后使用该数据构造它。您还可能认为通过值传递 float 通常比通过 const 引用更好的选择。浮点数可能是

标签: c++ class constructor


【解决方案1】:

成员的构造按照声明它们的顺序进行。这对于以下内容非常重要。如果声明的顺序与使用依赖的顺序不匹配,那么程序将有未定义的行为。

构造它们的初始化器可以在构造器的成员初始化器列表中指定在函数体之前的冒号之后:

void Tree::Tree(const std::istream& input)
  : height_(/* initializer for height_ */),
    leaf_(/* initializer for leaf_ */)
{
    //...
}

(也可以使用大括号代替括号来初始化列表。)

leaf_的初始化器中,可以使用height_的值。

由于您可能需要做一些工作才能从输入中获取height_,因此您可能需要为此编写一个额外的函数并将其调用为/* initializer for height_ */

【讨论】:

  • /*initialize for height_ */的额外函数可以是Tree的成员函数吗?
  • @P.Nair 是的,但请注意,在那个额外的函数中,height_leaf_ 都还没有构建,所以你不能在那里使用它们。
猜你喜欢
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 2012-08-15
  • 2014-01-28
  • 2017-02-02
  • 2011-12-07
  • 2011-03-06
  • 1970-01-01
相关资源
最近更新 更多