C++ Multiple Inheritance Constructor

Viewed 16831

I need to know something about the constructor. I didn't really know how to phrase the question, but basically I need to have all the action happening in the constructor of the final class, whilst a variable gets created in the constructor of one class and used in the constructor of another. Does this work, and is it safe? Example code below.

// Init class
class cInit {
private:
    std::string *m_X;

public:
    cInit() { m_X = new std::string; }
    std::string *getX() { return m_X; }
};

// Does this work (?)
class cUse {
private:
    std::string *m_X;

public:
    cUse(cInit *x) : m_X( x->getX() ) { }

// Final Class - same question here? Does it work?
class Final : public cInit, public cUse {
public:
    Final() : cInit(), cUse( this ) { }
}
2 Answers

I would prefer the following design (as it's more RAII oriented):

// Init class
class cInit {
private:
    std::string m_X;

public:
    cInit() : m_X() {}
    std::string & getX() { return m_X; }
};

class cUse {
private:
    std::string& m_X;

public:
    cUse(std::string &x) : m_X( x ) { }

// Final Class - same question here? Does it work?

In your sample you're using this, which isn't completely constructed at that point, though cInit already is. With vtables (virtual function definitions), usage of this will certainly fail.
Try the following instead:

class Final : public cInit, public cUse {
public:
    Final() : cInit(), cUse( cInit::getX() ) { }
}

You can also use pointers as in your original sample, but I'd strongly discourage to use raw pointers all along. Better choose a std::unique_ptr (std::auto_ptr with pre standard) for cInit::m_X and a raw pointer for cUse::m_X.

Since base constructors are called in declaration order, cInit::cInit() will be called first. Its constructor would assign cInit::m_X member.

Then, cUse::cUse(cInit *) will be called and would assign a result of call to cInit::getX() to cUse::m_X. Given that cInit::getX() is not a virtual function, it is safe to call it like that.

In other words, there is nothing wrong with this code. Except that it is ugly (or should I say not well designed?), confusing, and would only cause troubles further down the road.

Hope it helps.

Related