0

I'm a bit stuck with such awful problem of bad class hierarchy.

class A {...}; // abstract
class B : public A {...}; // abstract
class C {...}; // abstract

class a1 : public B, public C {...}; // indirect inheritance of A
class c1 : public A, public C {...};

The question: is it possible convert a pointer(reference) to C into pointer(reference) to class A.

I understand that best solution is to make just class C inherited from A, but still it can cause some problems with class a1 (two base A).

Nikita Smirnov
  • 813
  • 8
  • 17
  • C and A are completely unrelated, so no, you can't convert between the 2 with a static cast. You might be able to create a conversion operator for them though (or you could just re-design) – UKMonkey Dec 01 '17 at 12:10

3 Answers3

3

The question: is it possible convert a pointer(reference) to C into pointer(reference) to class A.

Not unless the classes are polymorphic i.e. have at least one virtual member function. In that case dynamic_cast can be used to side cast, as shown in StoryTeller's answer.

However, if that C pointer(reference) points to a child that inherits A, then you can first cast down to that child pointer, and then to A.

c1 c;
C& cref = c;
A& aref = static_cast<c1&>(cref);

That's of course not necessarily ideal because you cannot convert just any arbitrary C pointer whose concrete type is unknown.

I understand that best solution is to make just class C inherited from A

If you did this, then all C pointers would be implicitly convertible to A pointers.

but still it can cause some problems with class a1 (two base A).

To work around the problems, you need shared bases i.e virtual inheritance.

struct A {}; // abstract
struct B : virtual A {}; // abstract
struct C : virtual A {}; // abstract

struct a1 : B, C {}; // indirect inheritance of A
struct c1 : C {};

int main() {
    c1 c;
    C& cref = c;
    A& aref = cref;
}
eerorika
  • 232,697
  • 12
  • 197
  • 326
3

What you are trying to do is called a "side-cast". And the built-in dynamic_cast expression can do that. But it isn't cheap, and you better not have turned off support for RTTI in your project (you already mentioned your classes are abstract, so that entails virtual functions, whose declarations are needed for RTTI to be generated along).

See it Live

#include <cassert>

struct A {
    virtual ~A() = default;
};

struct B : public A {
    virtual ~B() = default;
};

struct C {
    virtual ~C() = default;
}; 

struct a1 : public B, public C {
    a1() = default;
    virtual ~a1() = default;

}; // indirect inheritance of A

int main() {
    a1 a;

    C* c = &a;

    assert(dynamic_cast<A*>(c) != nullptr);

    return 0;
}

But your sentiments about needing to re-design your classes are in my opinion highly warranted. The need to do a side cast should not arise.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
0

Both answers above are correct, but the first one is more widely explained, I think. Another solution that I will possibly use is creating a weird visitor, like:

PointerCreator
{
  void visit ( const a1 & _a )
  {
    m_pointerToA = &_a;
  }

  void visit ( const c1 & _c )
  {
    m_pointerToA = &_a;
  }

  A * m_pointerToA;
};

PointerCreator pC;
a1.accept( pC );
A& = *pC.m_pointerToA;
Nikita Smirnov
  • 813
  • 8
  • 17
  • Well, maybe sometime it could be useful... but I would not consider it as the usual way to do it. And if you do use a visitor, then you might prefer the visitor to do a specific action as it would be able to handle case where the is no target or multiple targets as appropriate... – Phil1970 Dec 02 '17 at 15:45