简体   繁体   中英

How to properly initialize non-default-constructible class member?

Assume I define a class Foo , which does not implement a default constructor. In addition, I have a class Bar , which "owns" an instance of 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 */
    }
};

The code as shown won't run, since Bar is trying to call the default constructor of Foo .

Now what I am trying to do is to have the constructor of Bar first determine something and then pass the result to the constructor of Foo .

One way to solve this is to have Bar only own a reference/pointer to Foo and initialize it after m_something was determined. However, I'd like to avoid that to make clear that the lifetime of m_foo is completely dependent on the lifetime of the owning class.

Another way would be to implement a default constructor in Foo and set the value later, which I would also like to avoid, since any instance of Foo should have a valid value for it's member (at any time).

What is the proper way to implement this? Am I stuck with a reference/pointer here?

The best idea will be to create helper function, that will calculate something and then just initialize m_foo in constructor initialized list.

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;
    }
};

Does this complex initialization code actually belong to Bar ? It may be good to consider having a separate class to just do this initializing. Something like

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  
}

This also opens the way to a full Builder pattern that might be useful in case, for example, you do not always need all that complex calculations.

This assumes all classes to be copy-constructible, but you may more-or-less easily modify it to support what you need.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM