Q-bertsuit
Q-bertsuit

Reputation: 3437

Construction of polymorphic classes

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

Answers (3)

Martin Meeser
Martin Meeser

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:

  1. Avoid method calls from the constructor. Use an additional init method for that.
  2. In any case beware of circular constructor calls.

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

pzed
pzed

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

n. m. could be an AI
n. m. could be an AI

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

Related Questions