What (not) to do in a constructor

tyrondis picture tyrondis · Oct 11, 2010 · Viewed 12.3k times · Source

I want to ask you for your best practices regarding constructors in C++. I am not quite sure what I should do in a constructor and what not.

Should I only use it for attribute initializations, calling parent constructors etc.? Or might I even put more complex functions into them like reading and parsing configuration data, setting up external libraries a.s.o.

Or should I write special functions for this? Resp. init() / cleanup()?

What are the PRO's and CON's here?

I figured out yet that for example I can get rid of shared pointers when using init() and cleanup(). I can create the objects on the stack as class attributes and initialize it later while it is already constructed.

If I handle it in the constructor I need to instantiate it during runtime. Then I need a pointer.

I really don't know how to decide.

Maybe you can help me out?

Answer

Stephane Rolland picture Stephane Rolland · Oct 11, 2010

The most common mistake to do in a constructor as well as in a destructor, is to use polymorphism. Polymorphism often does not work in constructors !

e.g.:

class A
{
public:
    A(){ doA();} 
    virtual void doA(){};
}

class B : public A
{
public:
    virtual void doA(){ doB();};
    void doB(){};   
}


void testB()
{
    B b; // this WON'T call doB();
}

this is because the object B is not yet constructed while performing the constructor of the mother class A... thus impossible for it to call the overriden version of void doA();


An example where polymorphism will work in constructor:

class A
{
public: 
    void callAPolymorphicBehaviour()
    {
        doOverridenBehaviour(); 
    }

    virtual void doOverridenBehaviour()
    {
        doA();
    }

    void doA(){}
};

class B : public A
{
public:
    B()
    {
        callAPolymorphicBehaviour();
    }

    virtual void doOverridenBehaviour()
    {
        doB()
    }

    void doB(){}
};

void testB()
{
   B b; // this WILL call doB();
}

This time, the reason behind is: at the time the virtual function doOverridenBehaviour() is invoked, the object b is already initialized (but not yet constructed), this means that its virtual table is initialized, and thus can perform polymorphism.