0

I have the following class called Tree, which has a member object of class Leaf. Leaf requires a parameter from Tree (height_) for its construction. I can write an intialize method for this. But do we know the order in which constructors are called, so that dependencies in the construction of member objects are met when the Tree class is constructed? In other words, when there is dependency in the instantiation of a member object, is an separate initialization method (for the member object) the only way to go? A minimal code below, I have put a question mark in the argument to the constructor of Leaf to indicate my question:

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; 
}
P. Nair
  • 79
  • 7
  • What does your text-book, tutorial or class-notes say about a *constructor initializer list*? – Some programmer dude Dec 22 '21 at 06:32
  • Does this answer your question? [Order of member constructor and destructor calls](https://stackoverflow.com/questions/2254263/order-of-member-constructor-and-destructor-calls) – Retired Ninja Dec 22 '21 at 06:34
  • @RetiredNinja the question is related, but in my case there is a dependency. My question is also if separate initialization method is the only option. I have edited the question to make this clear. – P. Nair Dec 22 '21 at 06:43
  • 1
    One school of thought is that you shouldn't do a lot of work in a constructor, so passing it a stream to parse is a bit of a code smell, and for you a problem because you seem to need the result of that parsing to initialize the members, You might consider a factory instead so that you can parse the data you need to construct the object and then construct it using that data. You also might consider that passing a `float` by value is generally a better choice than by const reference. A float is likely to be <= the size of a reference and avoids a dereference. – Retired Ninja Dec 22 '21 at 06:53

1 Answers1

0

Construction of the members happens in the order in which they are declared. This is very important for the following. If the order of declaration does not match the order in which the dependencies are used, then the program will have undefined behavior.

The initializers with which they are constructed can be specified in the member initializer list of the constructor after after a colon before the function body:

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

(Instead of parentheses, braces for list-initialization may also be used.)

In the initializer for leaf_, the value of height_ can be used.

Since you probably need to do some work to get height_ from the inputs, you probably want to write an extra function for that and call it for /* initializer for height_ */.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Can the extra function for /*initialize for height_ */ be a member function of Tree? – P. Nair Dec 22 '21 at 06:53
  • @P.Nair Yes, but be careful that in that extra function neither `height_` nor `leaf_` have been constructed yet, so you may not use them there. – user17732522 Dec 22 '21 at 06:55