Search code examples
c++inheritanceconstructorsiblingsreinterpret-cast

Construct parent from forward declared sibling without a reinterpret_cast


I'm trying to call a parent constructor, with a given pointer to sibling object:

class Base{
public:
    Base(const Base&) =default;    
};

#include "daughter.h"     // <-- problem! I'll come to this in a second.

class Son: public Base{
public:
    Son(Daughter* d) : Base(*d){};
};

But (and here comes the problem), this relationship goes in both directions:

// daughter.h
class Son;               // forward declare needed
class Daughter: public Base{
public:
    Daughter(Son* s) : Base(*d){};
};

Uh-oh: (link to run)

error: no matching function for call to 'Daughter::Daughter(Base&)'

note: candidates are:

note: Daughter::Daughter(const Base&)

note: no known conversion for argument 1 from 'Daughter' to 'const Base&'

So, the issue arises since at that point - where Son is an incomplete type - it is not known that it inherits from Base, and so this constructor doesn't match.

I have been able to 'solve' it:

Daughter::Daughter(Son* s) : Base( *reinterpret_cast<Base>(*s) ){};

But this seems bad practice - I don't think I should need to reinterpret_cast for something of such innocent intent - we all know Son will be a derived class of Base!

Is there a better way of dealing with this?

NB: While possibly true that it comes from bad overall design - "[I] shouldn't need to construct a parent from a sibling." - please bear in mind that I have reduced this to a very minimal example from a much larger design (with many more siblings, and many more constructors for each) in which doing this is necessary in a couple of places.


Solution

  • You have to define the constructors in cpp files to break the circular dependency:

    // base.h
    class Base {
    public:
        Base(const Base& b) { ... }
    };
    
    // son.h
    #include "base.h" // include because you need the definition for inheritance
    class Daughter;   // don't include, just forward declare
    class Son: public Base {
    public:
        Son(Daughter* d);
    };
    
    // son.cpp
    #include "son.h"
    #include "daughter.h"
    Son::Son(Daughter* d) : Base(*d) {}
    
    // daughter.h
    #include "base.h" // include because you need the definition for inheritance
    class Son;        // forward declare needed
    class Daughter: public Base {
    public:
        Daughter(Son* s);
    };
    
    // daughter.cpp
    #include "daughter.h"
    #include "son.h"
    Daughter::Daughter(Son* s) : Base(*s) {}