Q-bertsuit
Q-bertsuit

Reputation: 3437

Initializing variables in a class hierarchy

I got assigned the task to clean up a class hierarchy, but I'm stuck in a bit of a rut. I'm now left with something that roughly looks like this:

class Base
{
Base() = 0;

function1();
   ...
function5();

protected:

int variable1_;
   ...
int variable10_;
}; 

class DerivedOne
   : public Base
{
   DerivedOne() = 0;

   function6();
      ...
   function10();

 protected:

   int variable11_;
      ...
   int variable20_;
};

class DerivedTwo
   : public DerivedOne
{
    DerivedTwo()
       : DerivedOne() 
    {
       ... Fill variable1_ to variable25_ with data read from file ...
       variable1_ = ...
    }

    function11();
      ...
    function15();

  private:

    int variable21_;
      ...
    int variable25_;
};

So 25 variable are assigned their values in DerivedTwo, making it easy to make a mistake. When another class inherits from DerivedOne, it's almost certain that that person will forget to initialize one of the variables.

I've been playing around with different ways of designing this hierarchy, but nothing really feels right.

I understand it's difficult to say something concrete without knowing what these classes actually do, but I would be interested in knowing if there is something fundamental wrong with this design, or if I have overlooked some elegant way of initializing all the variables.

Upvotes: 0

Views: 274

Answers (2)

Christophe
Christophe

Reputation: 73456

The principle in derivation is that base object is constructed first, and the derived afterwards. This requires the Base and DerivedOne constructor to produce a valid object on its own.

When constructing DerivedTwo, your code makes this clear:

   DerivedTwo()
       : DerivedOne()  // First the base object constructor is called, before anything else 
   {
       // then remaining initialisation, after DerivedOne() was created
   }

So each class should at least initialise its own variables to an initial valid state that its own functions can handle in a consistent manner.

Base() : variable1_(/*default value here*/), variable10_(/*default value here*/) {}
Base(int v1, int v10) : variable1_(v1), variable10_(v10) {} // for convenience

One derived class could overwrite variables of its base class afterwards. It would of course be safer and more elegant to use getters/setters, but its ok.

If you adopt this design, if one subderived class forgets to initialise a variable one of its parents, this should not lead to a catastrophee because at least the base object is initialised in a decent manner.

Now the problem is that you also initiate your DerivedTwo by reading a file. Remember, first Base is created, then DerivedOne, and then only DerivedTwo reads the values. What happen when the file cannot be read or is unconsistent ? You might end up having an inconsistent object, unless your throw an exception. So you have to manage this and make sure that DerivedTwo is in a stable state:

   DerivedTwo()
       : DerivedOne()  // First the base object constructor is called 
   {
       // then initialise all own members to a consitent state
       // then try to read the file and manage potential errors 
   }

Upvotes: 1

pzed
pzed

Reputation: 837

Each class should be responsible for initializing its own data members. As you identified, it is dangerous for Base to assume that DerivedX will initialize its data members. So...

Base should initialize variable1_ ... variable10_

DerivedOne should initialize variable11_ ... variable20_

DerivedTwo should initialize variable21_ ... variable25_

...and so on.

Of course, this doesn't address the question of why the classes are laid out in such a fashion...

Upvotes: 0

Related Questions