3

I have the following situation :

class GenericObject{
virtual Attribute* getAttribute(){..}
}

class PlaneObject : public GenericObject{
Attribute1* getAttribute()override{..}
}

-----------------------------------------block1

class Attribute{
virtual GenericObject* getObject(){..}
}

class Attribute1 : public Attribute{
PlaneObject* getObject()override{..}
}

----------------------------------------block2

Since i'm overriding the getAttribute() methods in PlaneObject, changing its return type from Attribute* to Attribute1* , this is only allowed if the compiler is aware that Attribute1 is derived from Attribute.

Then I should put block2 before block1.

However, block2 also needs to know that PlaneObject is derived from GenericObject, in order to compile, because of the overridden methods in Attribute1 class.

I don't know if it is just bad design pattern or what. I've been looking for similar questions but didn't find the exact same picture i'm facing.

Usama Abdulrehman
  • 1,041
  • 3
  • 11
  • 21
Andrea Loforte
  • 117
  • 1
  • 10
  • Does this answer your question? [Forward declaration & circular dependency](https://stackoverflow.com/questions/16802485/forward-declaration-circular-dependency) – castro May 21 '20 at 19:29
  • 1
    You cannot forward declare inheritance, so it seems impossible to break your circular dependency – Jarod42 May 21 '20 at 19:30
  • 1
    @castro: more complicated than simple case, it would require to forward declare with inheritance, as OP use covariance return type. – Jarod42 May 21 '20 at 19:31
  • Most likely the design is headed in a questionable direction, but it's hard to say without knowing more about the intent. Both functions are `virtual`, so the correct functions will be called without knowing the exact type. The only use I see is if an object knows it holds an `Attribute1` and that `Attribute1` must hold a `PlaneObject`, and at that point this third object may know too much and be too specialized. – user4581301 May 21 '20 at 19:34
  • @Jarod42 it is entirely feasible to forward declare in this case, and IMO quite straightforward if each class is defined in its own header file, and each implementation is put in its own cpp file. Each header file only needs to forward declare one thing - the object it is returning. The subclass headers can safely include the base class headers and inherit as normal so there is no forward declaration of inheritance going on here as far as I can tell. – castro May 21 '20 at 20:19
  • @castro: Forward declaration is not enough for covariant return type [Demo](https://coliru.stacked-crooked.com/a/ac5f109fa89e75ac). – Jarod42 May 21 '20 at 20:51
  • @Jarod42 thanks for the demo, learnt something new today. Forgive my stubbornness, sometimes I have to see the errors for myself :D I guess then a potential solution is to avoid the covariant return types altogether and cast to the subclass where necessary. – castro May 21 '20 at 21:42

1 Answers1

2

there is no simple solution. you can try to break the cycle this way:

// GenericObject.h
class Attribute;
class GenericObject{
virtual Attribute* getAttribute();
};

// Attribute.h
class GenericObject;
class Attribute{
virtual GenericObject* getObject();
};

// PlaneObject.h
#include "GenericObject.h"
class Attribute1;
class PlaneObject : public GenericObject
{
Attribute* getAttribute()override;
Attribute1* getAttributeRealType();
};

// Attribute1.h
#include "Attribute.h"
class PlaneObject;
class Attribute1 : public Attribute{
GenericObject* getObject()override;
PlaneObject* getObjectRealType();
};

// implementation example
// PlaneObject.cpp
#include "PlaneObject.h"
#include "Attrubute1.h"
Attribute* PlaneObject::getAttribute()
{
    return getAttributeRealType();
}
Attribute1* PlaneObject::getAttributeRealType()
{
    return new Attribute1;
}
// attribute1.cpp
#include "Attribute1.h"
#include "PlaneObject.h"
GenericObject* Attribute1::getObject()
{
   return getObjectRealType();
}
PlaneObject* Attribute1::getObjectRealType()
{
   return new PlaneObject;
}
Alexander
  • 698
  • 6
  • 14
  • does getObjectRealType() do a static_cast ? it might be a work around even if i'm not a super fan of casting. – Andrea Loforte May 21 '20 at 19:45
  • @AndreaLoforte implementation (no static_cast at all): `GenericObject* getObject() { return getObjectRealType(); } PlaneObject* getObjectRealType() { return yourObject; }` – Alexander May 21 '20 at 19:47
  • 1
    @castro i do not see how the code can be simpler. the example is almost fully divided into h and cpp. i can draw borderlines if needed. – Alexander May 21 '20 at 20:38
  • sorry the code is very clear. My fault. And btway it is a nice work around. Besides, i couldn't find different solutions at the moment , so, thank you. – Andrea Loforte May 21 '20 at 21:59
  • @Alexander I deleted my comment before I saw your reply. I wasn't saying the code itself could be simplified, merely that it is simpler to work with if the definitions and declarations are put in separate files. In any case your edit helps in this regard. – castro May 22 '20 at 06:45