Reputation: 2815
I have three classes that inherit as follows:
Class_A
Class_B : public Class_A
Class_C : public Class_B
Class_A
contains a constructor:
public: Class_A(const char *name, int kind);
Class_B
does not contain that constructor.
In Class_C
I wish to invoke the constructor of Class_A. Something like:
Class_C(const char *name, int kind) : Class_A::Class_A(name,kind) {
}
The problem is that I cannot add an intermediate constructor to Class_B
, because Class_B
is generated code that regenerates every time I make clean. So I cannot make any lasting changes to Class_B
. Needless to say, the above line of the constructor in Class_C
gives the error: "type 'Class_A' is not a direct base of '
Class_C'".
Is there a way that I may invoke the constructor of Class_A
in the subclass Class_C
, without requiring the same type of constructor in Class_B
?
Upvotes: 6
Views: 240
Reputation: 153909
The only possibility would be for Class_B
to inherit virtually from
Class_A
; in that case, the constructor for Class_A
would be called
from the most derived class. But since this would also involve changing
the code generator, or the input to the code generator, you might as
well change it to add the additional constructor to Class_B
.
If you really can't change the code generator or its input in a way that
would cause it to generate the additional constructor, but you can
change Class_A
and Class_C
, then there are two possible solutions:
Class_A
which takes the appropriate parameters, and does the
initialization after the constructor has finished. While the simplest,
this method can only be used if Class_A
can be made to support default
construction as well, and if all of the members of Class_A
support
assignment, with semantics such that default construction followed
by assignment has the same result as construction using the arguments
you give (i.e. no reference members, no noncopiable members, no
const
members, etc.).
Class_A
in a separate class, and have Class_A
derive from this class virtually. Class_C
will then call the
constructor of this new class.
Upvotes: 1
Reputation: 106076
You're probably stuffed (assuming you can't change class B's generation), but if there happen to be any constructors for B that are templates, then you can specialise one (for a unique dummy class) and create your own custom constructor with whatever base-class-A construction you feel like....
Otherwise, while less efficient, the obvious, safe, clean approach is to use A's operator=
(if any) to get the value you want into it...
C c;
c = A(x, y);
If those fields of A can only be set at construction time, then it's a harder problem....
(Stepping momentarily and deeply into the dreaded land of Undefined Behaviour, you could invoke A's destructor then placement new
it, but A's lifespan is meant to span Bs and Cs. Practically, the obvious risk is that A created something like a heap-allocated value that B or C already holds a pointer to and may try to use after A destructor releases it....)
Upvotes: 1
Reputation: 31851
If you can make the base class a virtual base class you can do this, as virtual bases must always uninitialized in the outermost constructor directly. If you can't change how ClassB inherits from A you can always do this:
RealClassA
ClassA : public virtual RealClassA
ClassB : public ClassA
ClassC : public ClassB
Then in the ClassC constructor you can call RealClassA(...)
directly.
Usually this feature of virtual inheritence is a real pain, but it might actually help you here.
Upvotes: 1
Reputation: 69988
By language one cannot access non-immediate base constructors.
By the way, If Class_A
constructor signature is,
Class_A(const char *name, int kind);
then, Class_B
should have some constructor which will entertain the Class_A
constructor of the given type. Otherwise it will give compiler error.
The only way to get rid of that error is to provide default arguments to Class_A::Class_A(...)
.
Upvotes: 0
Reputation: 9612
You could add a constructor for Class_B
, which has the same signature as ctor of Class_A
, and then let Class_C
call that in ctor.
Besides, a class ctor initialization list could not set values for members in base class (no matter they are private
protected
or public
). You must use the base class' ctor to set them.
Upvotes: 0
Reputation: 7132
If B is generated, then change the generator, otherwise you're doomed.
Depending on what B is doing, might be a solution to change your design to have C derivation from A and B directly (if A is your container class and B a processing class). Doing this, might require you to template B. If B needs to act on A members, you can still give an A pointer to B constructor...
Upvotes: 0
Reputation: 131789
If you can't change the code that generates B
, then you are out of luck, AFAIK. But if the A
class contains such a constructor, maybe you can get away with adding a simple member function that sets those two variables and call it from inside the C
constructor? May not be as efficient as it gets, but atleast it works.
Upvotes: 4