2

Is it a bad design to have a derived class ctor receiving in the parameters a copy of the base class to avoid rewriting all base class ctor parameters again in the derived class ctor?

Say you have:

class CBase
{
public:
    int a1;
    int a2;
    int a3;

    CBase(int _a1, int _a2, int _a3) :
        a1(_a1), a2(_a2), a3(_a3)
    {}
};

class CDerived : public CBase
{
public:
    int b1;
    int b2;

    CDerived(int _a1, int _a2, int _a3, int _b1, int _b2) :
        CBase(_a1, _a2, _a3), b1(_b1), b2(_b2)
    {}
};

The CDerived ctor seems very wrong. What is recommended to do in this situation? I thought to change the CDerived ctor to something like this:

class CDerived : public CBase
{
public:
    int b1;
    int b2;

    CDerived(CBase _cbase, int _b1, int _b2) :
        CBase(_cbase), b1(_b1), b2(_b2)
    {}
};

Is this wrong?

underthevoid
  • 513
  • 1
  • 6
  • 17
  • It is not necessary wrong, but it is probably not a good idea. You should accept a reference to (const-qualified) base class. Related: [What is object slicing?](https://stackoverflow.com/questions/274626/what-is-object-slicing) – user7860670 Mar 04 '19 at 07:46
  • You define a new constructor with new parameters; you are responsible for properly constructing the base class (solution 1). Your last solution is horrible, don't do that. – rustyx Mar 04 '19 at 07:51
  • @rustyx So there are not a clean native solution to avoid rewriting all base class ctor param list in the derived class ctor? – underthevoid Mar 04 '19 at 08:08
  • Do you have good reason to use inheritance? Otherwise `CBase` could be an Member of `CDerived` and the second approach would be fine. –  Mar 04 '19 at 08:31
  • @generic_opto_guy Yes, because CBase is the base class of some other derived classes. The code makes use of polymorphic functions in CBase. – underthevoid Mar 04 '19 at 08:37

2 Answers2

2

It is not by itself wrong. However this strongly suggest that the design is flawed, and in particular that its author might not have applied properly composition over inheritance.

To illustrate the problem with some less abstract pseudocode:

Rocket myrocket(1000); 
Booster mybooster1(200), mybooster2(200);

// should I really copy my rocket to add boosters ??? 
SuperRocket mynewrocket(myrocket, mybooster1, mybooster2); 

// or should I construct it with the boosters ? 
SuperRocket myrocket(1000, mybooster1, mybooster2);

// or should I make this more flexible
SuperRocket myrocket(1000);  
myrocket.add(mybooster1);
myrocket.add(mybooster2); 
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • Hmm very nice idea. Didn't know about that, thanks for sharing. Although lets stick with my example (imagine a similar situation where it applies). What is the right approach to deal with the derived class having to rewrite all base class ctor parameter list (assuming it have a big param list)? – underthevoid Mar 04 '19 at 08:05
  • 1
    I just added some pseudocode to show alternatives. It all depend on the meaning of those classes: is the derived a kind of composition with the base class being part of it ? is the derived a class that adds some responsibilities to the base class ? is the derived a proxy of the base ? It's difficult to give a better advice at this level of abstraction. – Christophe Mar 04 '19 at 08:09
  • I see. Lets imagine a context where the base classe have to initialize all its variables in its ctor and the same should happen in the derived class ctor; lets say these classes have a lot of variables and all of them must be initialized at object-instantiation-time. What would be the right approach in this case? – underthevoid Mar 04 '19 at 08:15
  • @underthevoid I think that the construction process should not drive the class design, but the class design should guide the constructor. I also think that a shortcut in parameter passing is not a valid argument for deciding on constructor design. The question is whether it makes sense or not to construct a derived by copying and extending a base object. If this is meaningful, go for it. But If the problem is essentially about a complex construction, with lots of parts/subobject that must be available right at the instantiation, then just provide the args, or consider the builder pattern. – Christophe Mar 04 '19 at 08:53
-1

Your first approach is fine. There's nothing wrong with it. However, when the number of parameters exceed 5, it's recommended to use the builder pattern.

The second alternative doesn't make sense. You're indirectly forcing the caller of your derived class to pass in an object of the base class in the constructor. This is a bad practice as you are leaking the details of your base class in the derived class.

You should stick to the first approach.

isopropylcyanide
  • 423
  • 4
  • 16