Here's my issue, simplified:
enum AnimalType_t { DOG = 0, GREY_HOUND = 1, IMMORTAL_JELLYFISH = 2, }; struct RawData_t { int age; AnimalType_t typeOfAnimal; }; RawData_t GetMyCurrentRawData();//returns the current raw data bool IsDataReady(); //returns true if data is ready, false otherwise
class Animal { public: virtual Animal(); virtual ~Animal(); int GetType() { return rawAttributes.typeOfAnimal; }; //the only implementation for all children virtual int GetAge() { return rawAttributes.age; }; //to be implemented in the child class virtual void UpdateAge() { rawAttributes.age++; }; //to be implemented in the child class virtual int GetNumberOfLegs() = 0; //to be implemented in the child class private: RawData_t rawAttributes; }
class Dog : public Animal { public: Dog(RawData rawData):Animal(rawData){}; int GetNumberOfLegs() {return 4;}; }; class GreyHound : public Dog { public: GreyHound(RawData rawData):Dog(rawData){}; }; class ImmortalJellyFish : public Animal { public: ImmortalJellyFish(RawData rawData):Animal(rawData){}; int GetNumberOfLegs() {return 0;}; void UpdateAge() { return;} override; };
class Building { public: Building(){}; //sorry for the long line, but you get the idea... int Display(void){if(IsDataReady()) DisplayOnScreen("This animal ( "+ animal_m.GetType()+") has " + animal_m.GetNumberOfLegs() + "legs and is " + animal_m.GetAge() + " years old\n";}; int Live(void){currentDiagCode_m.UpdateAge();}; private: auto animal_m; //?? not working }; static Building paddock; static Building farm; void Buildings_Step(void) { paddock.Live(); paddock.Display(); farm.Live(); farm.Display(); }
Here's where i'm struggling:
Here're my constraints:
I though about :
Is there any design/model that could fulfill my needs?
Thank you!
In C++, memory allocation and object existence are two separate concepts, even though in most situations you'll handle both together. In your case, though, you may wish to explicitly separate the two:
Create enough memory for any object:
char buf[N]; // N >= sizeof(T) for all T in your hierarchy
To create an animal:
new (buf) GreyHound(args);
To destroy an existing animal (and make room for another):
reinterpret_cast<Animal*>(buf)->~Animal();
That is, you obtain storage as part of your container object, but you manage the Animal object lifetime dynamically with placement-new and explicit destruction.
There's a bit more to this: your memory also needs to be aligned correctly for all types that you construct in it. You can use some library helper traits like std::aligned_storage
or std::aligned_union
to simplify the computation, though you'll probably still need to do a bit of work to compute both the size and the alignment.
As a completely separate alternative, you could forego the polymorphic class hierarchy and use a std::variant
instead. This is conceptually similar, but a somewhat different approach implementation-wise. The reason that this is conceptually similar is because you have a bounded set of types, so you don't really need polymorphism to handle arbitrary, unknown derived types at runtime.