tags:

views:

92

answers:

3

Hi,

I find my self repeating a single line of code in child constructors, which are passed two variables. The first of these variables is always used to initiate a protected variable (defined in the parent class). I was wondering if there is a way for me to do that assignment in the parent constructor - which is then inherited, and do the rest of the assinments for the child class in each of the respective constructors (in the child classes)

is this possible? and is this good practice?

many thanks

+3  A: 

If I understand you correctly, you need something like this

class Parent
{
public:
  Parent(int Param1, doubel param2)
    :param1(Param1), param2(Param2)
{
}
protected:
  int param1;
  double param2;
};

class Derived: public Parent
{
public:
  Derived(int Param1, doubel param2)
    :Parent(Param1, Param2)
  {
  } 
};

I would recommend to keep param1 and param2 private and expose them to derived classes via methods, though it depends of your particular task at hand.

Oleg Zhylin
+1 for suggesting to keep variables private
xtofl
+2  A: 

Do you mean something like this?

class Parent {
  Parent(const Foo& x) : x(x) {}
  Foo x;
};

class Child : Parent {
  Child(const Foo& x, const Bar& y) : Parent(x), y(y) {}
  Bar y;
};

If Parent owns the variable, make Parent's constructor initialize it. Then Your Child class just has to pass the variable to Parent's constructor.

jalf
A: 

If you mean to fix this

// an example base class, forcing some invariant on it's state
class Base {
   int i; // guaranteed to be zero or MAXINT
public:
   Base( bool isClear ): i( isClear ? 0 : MAXINT ) {} 
   void increment() { i = MAXINT; }
   void decrement() { i = 0; }

   bool isMax() const { return i == MAXINT; }
   bool isZero() const { return i == 0; }
   void checkInvariants() const { assert( isMax() || isZero() ); }
};

class Sub : public Base {
public:
   Sub( int intended_i ) : i(intended_i) {} // error: i not accessible! 
};

By making the Base::i member protected, you're in for a piece of fragile design. It's the Base class' responsibility to initialize it's members. When opening up the members to subclasses or to the public, Base can no longer guarantee that it's members are subject to it's invariant.

In the above code, this would mean that certain instances of Base can fail to 'act' like Base instances:

Sub s( 10 );
s.checkInvariants(); // will trigger the assert!

On top of that, the subclass will have to be changed when deciding to change members in the superclass.

Subclasses are really also clients of the base class. They should access the same interface as the client code. This keeps the design flexible (loose coupling).

A way to get around copying constructor arguments over and over again is wrapping it in a structure. Especially when you suspect the Base class to be subject to change frequently, this can separate the concerns a lot:

class Base {
  int i;
public:
    struct Args { bool isClear; };
    Base( const Args & args ): i( args.isClear ? 0 : MAXINT ) {}
};

class Sub {
   bool b;
public:
   struct Args { Base::Args base; bool b; };
   Sub( const Args& args ): Base( args.base ), b( args.b ) {}
};

Now, adding a member to the base class becomes possible without changing the subclass: simply extend the Base::Args structure, and you're done. (Note: the client code will still need to fill in the extra arguments for the base class).

xtofl