Didii
Didii

Reputation: 1363

About abstract class design

I currently have this structure, where Collider is an abstract class.

Collider class structure

I want to create another abstract class LevelObj which should have a Collider. Any inherited classes of LevelObj, such as Wall, then has to further define which one of the colliders it needs. Then I wanted to create the object Level which has a container of LevelObj. This way I would have access to all functions of both Collider and LevelObj from Level.

This method however is not possible, since LevelObj cannot hold an abstract class. And even if it could, I would not be able to 'change' the object Collider in any of his children for the inherited classes of LevelObj.

Is there any way to achieve the same result?

Upvotes: 3

Views: 130

Answers (2)

jsantander
jsantander

Reputation: 5102

You cannot create an instance of an abstract class. ... but you can have a pointer or pointer-like type to the abstract class, that at run time time gets to point to instances of the derived classes (that can be instantiated because they're not abstract)

So you have a choice of

  • pointers: You must deal with the ownership, i.e. who must have the task of creating/destroying that instance.
  • references: I don't feel comfortable with references as attributes. A reference is more or less like a pointer, but it uses different syntax... and cannot be null... So your control of the lifecylce of the referenced object must be tighter.
  • higher level (dealing on its way with the lifecycle of the referenced objects), unique_ptr, shared_ptr...

All of them can point to an instance of any of the derived classes... and accessing it as an abstract class

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727077

This method however is not possible, since LevelObj cannot hold an abstract class.

That is certainly true. However, it can hold a pointer or a reference to an object of an abstract class. The actual object can be embedded in the derived class, like this:

class LevelObj {
public:
    Collider &collider;
protected:
    LevelObj(Collider &c) : collider(c) {}
};
class Wall : public LevelObj {
private:
    ColliderRect wallCollider;
public:
    Wall() : LevelObj(wallCollider) {}
};
class Fence : public LevelObj {
private:
    ColliderMesh fenceCollider;
public:
    Fence() : LevelObj(fenceCollider) {}
};

The above assumes that subclasses of LevelObj are "married" to their colliders. If that is not true, use unique_ptr<Collider> in the base, and initialize it from the constructor of the derived class by supplying a pointer to an allocated collider to the base class.

Then I wanted to create the object Level which has a container of LevelObj

Since LevelObj is polymorphic, you should use a container of smart pointers to LevelObj - unique_ptr<LevelObj> if level objects are not shared among levels (or within the same level) or shared_ptr<LevelObj> if level objects are shared in any way.

Upvotes: 1

Related Questions