Search code examples
c++constructorconstantsctor-initializer

initializing const fields in the constructor


const fields in C++ must be initialized in the initialization list, this makes non trivial the computation of interdependent values from the constructor parameters.

What is(are) the best way(s) to translate, for example, this piece of java code into c++ ?

public class SomeObject {
  private final String some_string;
  private final int some_int;

  public SomeObject(final String input_filename){
    SomeReader reader(input_filename);

    some_string = reader.getString();
    some_int = reader.getInt();

    reader.close();
  }
}

I thought of encapsulating a sub-object in SomeObject, but this is just shifting the problem; or constructing the object using a static method:

class SomeObject {
  private:
    const std::string some_string;
    const int some_int;

  public:
    static SomeObject unserialize(const char * input_filename){
      SomeReader reader = new SomeReader(input_filename);

      string str = reader.get_string();
      int i = reader.get_int();

      reader.close();

      SomeObject obj(str, i);
      return obj;
    };

    SomeObject(const std::string str, const int i) :
      some_string(str),
      some_int(i)
    {};
}

Is there a better solution ?

Thank you.


Solution

  • This is a great application for C++11 constructor delegation:

    class SomeObject {
      private:
        const std::string some_string;
        const int some_int;
    
      public:
        // The "real" constructor for SomeObject
        SomeObject(std::string str, const int i) :
          some_string{std::move(str)},
          some_int{i}
        {}
    
        // Deserialize from SomeReader (delegates to the primary constructor)
        SomeObject(SomeReader& reader) :
          SomeObject{reader.get_string(), reader.get_int()} {}
    
        // Deserialize from SomeReader (accepts rvalues,
        //   delegates to the lvalue constructor)
        SomeObject(SomeReader&& reader) :
          SomeObject{reader} {}
    
        // Deserialize from named file (delegates to the SomeReader&& constructor)
        SomeObject(const char* input_filename) :
          SomeObject{SomeReader{input_filename}} {}
    };