Prevent instantiation of base class with no pure virtual methods

Started by
19 comments, last by Quasimojo 10 years, 10 months ago

Yup, I dun' did a typo in my post, corrected now.

You still need to call the base class constructor, so all your derived classes need a constructor. How else could you construct a derived class? If you have a default constructor for the base class that would be OK but you haven't.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley
Advertisement


You still need to call the base class constructor, so all your derived classes need a constructor. How else could you construct a derived class? If you have a default constructor for the base class that would be OK but you haven't.

What do I need to do to the constructor I've declared in the base class to cause it to be used as the default constructor for derived classes?


What do I need to do to the constructor I've declared in the base class to cause it to be used as the default constructor for derived classes?

A default constructor has no parameters.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]


What do I need to do to the constructor I've declared in the base class to cause it to be used as the default constructor for derived classes?

A default constructor has no parameters.

Or it has all optional parameters. As long as it can be called without any arguments it is a default constructor.

You can't use a default constructor in this case because you need to use different IDs for each derived class.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

I should point out that I don't quite understand why you would want a base class with no virtual functions. If you are not going to use polymorphism here, what's the point of using inheritance?

Every derived class will have the data members, EntityID and TypeID. Beyond that, they will each have additional data members specific to their purposes. The only functionality I've determined they will all share is the assignment of EntityID and TypeID upon instantiation, but it doesn't sound like I can accomplish that from the base class definition.

If there is a better way to accomplish this, I'd appreciate it if someone could modify my design above to illustrate.

I see. So you would be happy to have a struct called Identification that contains EntityID and TypeID, and have every class have a member of that type, except you would then have to say object.identification.EntityID instead of simply object.EntityID.

I strongly recommend sacrificing a few bytes and structuring your code in the simpler way.

I should point out that I don't quite understand why you would want a base class with no virtual functions. If you are not going to use polymorphism here, what's the point of using inheritance?


Every derived class will have the data members, EntityID and TypeID. Beyond that, they will each have additional data members specific to their purposes. The only functionality I've determined they will all share is the assignment of EntityID and TypeID upon instantiation, but it doesn't sound like I can accomplish that from the base class definition.

If there is a better way to accomplish this, I'd appreciate it if someone could modify my design above to illustrate.
In that case you are not specifying an implementation, you are specifying an interface.


However, for all the component systems I've worked on over the years, it is almost certain that your base class will pick up all kinds of wonderful functionality. This is a good thing. All components may be serialized. All components may get updated. All components may have signals and slots. All components may have visualization methods, at the very least to handle component names and properties during debugging. All components in your game will do this, that, and something else. It should absolutely be made into an abstract base class for your purposes. (That includes the virtual destructor, which is basically mandatory on any class meant for inheritance.)

Just to make sure I understand correctly, there is no way to declare a constructor that assigns values to data members in an abstract base class that will provide that default constructor functionality in all derived classes, correct? Therefore, all derived classes will have to have the same constructor declared:


class DerivedComponent1{
    public:
        DerivedComponent1(long entityID, ComponentType compType) : EntityID(entityID), TypeID(compType) {}
       ~DerivedComponent1();    // Because it's just good practice

        long EnityID;
        ComponentType TypeID;
};

class DerivedComponent2{
    public:
        DerivedComponent2(long entityID, ComponentType compType) : EntityID(entityID), TypeID(compType) {}
       ~DerivedComponent2();

        long EnityID;
        ComponentType TypeID;
};

Therefore, all derived classes will have to have the same constructor declared

Not quite. The base class needs to define and initialise the data members, and the derived classes' constructors should call the base class' constructor:
class Component {
public:
    Component(long entityID, ComponentType compType) : entityID(entityID), compType(compType) {}

    long entityID;
    ComponentType compType;
};

class DerivedComponent : public Component {
public:
    Derived(long entityID, ComponentType compType) : Component(entityID, compType) {}
};

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

In my component system I also used to have entityId and typeId. However, after some refactoring I did, I realized I didn't need them at all anymore! Any code that is operating on a Component already knows what type it is (or doesn't care), and knows which entity it came from. So I ended up removing them (saving 8 bytes per component). This will really depend on your particular implementation though (I see more reason for requiring entityId than typeId).

In my case I still have a Component base class. But it only contains pure virtual functions (mainly for serialization, which subclasses are required to implement, and also for a Reset() method, since I pool and re-use components).


Though in this case you might consider instead of the type id being a member variable, making the type id a virtual function that the child classes implement. This would also be a good candidate for a pure virtual function.

That saves memory, at the cost of requiring a virtual method call every time you need to get the type id. Not saying that's good or bad, but that's something to think about.

Though in this case you might consider instead of the type id being a member variable, making the type id a virtual function that the child classes implement. This would also be a good candidate for a pure virtual function.

That saves memory, at the cost of requiring a virtual method call every time you need to get the type id. Not saying that's good or bad, but that's something to think about.

Type id should be the same for all instances of a given component. We're getting out of For Beginners territory here, but it might be a good candidate to make a template parameter of the base class.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This topic is closed to new replies.

Advertisement