1

I frequently have to face the scenario of a class containing several const variables, which need to be initialized in the initialization list, but also need some other method in advance to calculate the values.

For example, for the following class:

class Base
{
    protected:
        const int a, b;
    public:
        Base(string file);
};

I want the constructor to extract some variables by parsing the file, and then assign the extracted values to the const variables (a and b). I used to spoil the comma operator a lot (use comma operator to initialize the base class), but found very inconvenient for more complicated cases. Any suggestions about some more elegant solutions?

Community
  • 1
  • 1
Hailiang Zhang
  • 17,604
  • 23
  • 71
  • 117

1 Answers1

5

In simple cases where you need to parse one object to compute the value for one data member, I'd supply a free function and call that:

int ComputeAFromFile (const string& file)
{
  // MAGIC
}

class Base
{
    protected:
        const int a;
    public:
        Base(string file) : a (ComputeAFromFile (file)) {}
};

This breaks down when you need to parse one object to compute the values of more than one member, however:

int ComputeAFromFile (const string& file)
{
  // MAGIC
}

int ComputeBFromFile (const string& file)
{
  // MORE MAGIC
}


class Base
{
    protected:
        const int a, b;
    public:
        Base(string file) 
  : 
    a (ComputeAFromFile (file)) 
    b (ComputeBFromFile (file)) 
  {
  }
};

You could do this, and it's certainly simple (read: easy to understand & maintain), but its also costly in terms of having to parse the same file twice.

So instead, what I'll often do is build a kind of intermediary object that parses the file once on construction, and caches the extracted values:

class FileParser 
{
public:
  FileParser (const string& file)
  {
    Parse (file);
  }

  int GetA () const { return mA; }
  int GetB () const { return mB; }

private:
  int mA;
  int mB;

  void Parse (const string& file)
  {
    // MAGIC HAPPENS!
    // Parse the file, compute mA and mB, then return
  }
};

Now, instead of Base taking a string on construction, it can take a FileParser:

class Base
{
public:
  Base (const FileParser& parser)
  :
    a (parser.GetA()),
    b (parser.GetB())
  {
  }
};

And Base is constructed thusly:

string file = ...;
Base b (FileParser (file));
John Dibling
  • 99,718
  • 31
  • 186
  • 324