Reputation: 3437
I have a question about the way classes using inheritance are constructed. In the example below, the call to the Base
constructor is dependent on a function implemented in the Derived
class. This function is again dependent on the Derived
member generator
, which will not be initialized until after the Base
constructor call.
If the Base
class is constructed first, won't the variable Base::in_
contain garbage data?
class Derived
: public Base
{
Derived()
: Base(get_data()),
generator(5) {}
Generator generator;
int get_data() { return generator.get_some_data(); }
};
class Base
{
Base(int in)
: in_(in) {}
int in_;
}
Upvotes: 2
Views: 847
Reputation: 2956
I have no idea what the standard says, but this is clearly a matter of what is the value of generator
when get_data()
is called, as it would be if you call it from somewhere else then the constructor.
Code called from within a constructor is no way different to other code.
My guess is that get_data() is called before generator is constructed and thus you will get a NULL exception at runtime.
Another point to mention is that the base class is of course being constructed first. It is the base class. Derived
IS A Base
, it has a field in_
.
As a rule of thumb it is always a good pattern to:
You also could make get_data
abstract in Base
and then call it within the Init()
of Base
which would IMHO be the right way to implement a dependency to child classes as you call it.
class Derived
: public Base
{
Derived()
: Base(),
generator(5) {}
Generator generator;
virtual int get_data() { return generator.get_some_data(); }
};
class Base
{
Base()
{
}
Init() {
in_ = get_data();}
int in_;
virtual int get_data() = 0;
}
Upvotes: 0
Reputation: 837
See Order of calling constructors/destructors in inheritance
The constructor for Base will be called before any members of Derived are initialized. So generator will not have been initialized when get_data() is called.
Basically, Base will be initialized with garbage.
Upvotes: 0
Reputation: 119847
First, nothing in your code is polymorphic. Polymorphism is about virtual functions.
Next, your class Base
depends on nothing. Look between class Base {
and the matching }
, there's nothing in there that depends on anything outside.
What happens is the construction of the Base
subobject within Derived
depends on another member of Derived, which is constructed after Base
. Your analysis is basically correct, it's a real problem and it needs to be solved by refactoring your classes.
The easiest way is two-stage initialization of Base (the following is pseudocode and probably will not compile):
class Base {
Base(int in = 0) : in_(in) {}
void set(int in) { in_ = in; }
int in_;
};
class Derived : public Base {
Derived() : Base(), generator(5) {
Base::set(generator);
}
...
};
Another method is moving the dependency to another base class:
class Base2 { ... generator implemented here ... };
class Derived : public Base2, public Base {
Derived() : Base2(5), Base(Base2::generator) {}
};
Upvotes: 2