4

I have different collections of Components, where each Component subclasses an abstract class IComponent.IComponent defines a pure virtual function virtual ID_TYPE getId() = 0;, so each component need to create an implementation for it.

Consider each Component may only be added once, so its ID equals for all instances and a collection function

IComponent* ICollection::getComponent(const ID_TYPE);

I want to have an additional static method just like the one described above in order to retrieve the ID of a component without the need to create an instance (there might be no default constructor) in order to something like

collection1.getComponent(MyComponentA::getId())->something();
collection2.getComponent(MyComponentA::getId())->something();

I know there aren't such things as virtual static members, and a static method cannot be overridden. But might there be any other way to ensure each subclass of IComponent defines such a static method?

5
  • How can anything know the ID of a Component that doesn't exist (it hasn't been ceated)?
    – Paul Evans
    Commented Apr 25, 2014 at 11:23
  • If you call it and it doesn't exist, you will get a compilation error, so I don't quite get what the problem is. (And it's "overridden", not "overwritten", because the verb is "override".)
    – molbdnilo
    Commented Apr 25, 2014 at 11:27
  • @PaulEvans the ID is static and unique for each component
    – muffel
    Commented Apr 25, 2014 at 11:29
  • Likely C++ traits concept can be used in this case Commented Apr 25, 2014 at 11:36
  • You can do what you want by creating multiple methods like so : stackoverflow.com/a/1820676/1098041 I'm not sure this is good practice though. Commented Apr 25, 2014 at 12:25

3 Answers 3

2

So I would go with something like this:

ComponentBase.h:

template <typename T>
class ComponentBase {
   ....
   .... 
protected:
   ComponentBase() { (void)getClassId(); }
public:
   static int getClassId();
   ....
};

Component1.h:

#include "ComponentBase.h"

class Component1: public ComponentBase<Component1> {
public:
    Component1(....) {}
    ....
};

Component1.cc:

#include "Component1.h"

....

template <>
int ComponentBase<Component1>::getClassId() {
    return 1;
}

If a developer forgets to define ComponentBase<ComponentX>::getClass() for a class ComponentX, the project won't link.

Actually I wouldn't leave the choice of the ID to a component developer. This technique allows provide a common implementation based solely on the ComponentX class name, thus getting the uniсity of the ID "for free".

0

One way is to make some template magic in case you can modify the IComponent interface and your classes. Something like:

#include <iostream>

using namespace std;
typedef int ID_TYPE;

class IComponent
{
public:
    IComponent() {}

    template <class T>
    ID_TYPE gclassId()
    {
        return T::classId(); 

    }

    virtual ID_TYPE getId() = 0;
};

class Comp1 : public IComponent
{
public:
    Comp1() {}
    virtual ID_TYPE getId() {return IComponent::gclassId<Comp1>();}
    static ID_TYPE classId() {return 1; }
};

class Comp2 : public IComponent
{
public:
    Comp2() {}
    virtual ID_TYPE getId() {return IComponent::gclassId<Comp2>(); }
    static ID_TYPE classId() {return 2;}
};

    /*
class Comp3 : public IComponent
{
public:
    Comp3() {}
    virtual ID_TYPE getId() {return IComponent::gclassId<Comp3>(); }
};
    */

int main()
{
    Comp1 a;
    Comp2 b;
    IComponent* t = new Comp2();
    std::cout << a.getId() << t->getId();
    delete t;
    return 0;
}

This requries you that each IComponent derived class declares a static member, classId(). If you uncomment Comp3 you will get a compilation error.

By modify it I mean you have access to the source code. Please ignore the typedef for your ID_TYPE, it can be whatever you want it to be, as long as your virtual functions return the real ID via the gclassId from the IComponent which in its turn goes to the mandatory static method from the class.

2
  • This isn't bad. It at least forces the definition of the static as fritzone says. It still wouldn't force a derived class to use it and IComponent wouldn't be a pure interface anymore since it would contain an implementation. I'm not sure if it would be worth the added complexity to me, but it is creative.
    – brader24
    Commented Apr 25, 2014 at 11:39
  • @brader24 Yes, that's true, it does not enforce the usage of it, but it gives clear guidelines on how to use it, and actually using it is up to the programmer implementing the components. Commented Apr 25, 2014 at 11:41
0

I don't know of any way to force a derived class to implement a member except through pure virtual methods.

I would recommend simply using a pure virtual or similar with documentation to indicate that the ID should be unique to the class implementation not to the class instance. In an ideal world you should be able to count on developers of a derived class to read the documentation of a method to know that it needs to return a static identifier and not an instance identifier. You have to count on them to implement other pure virtual methods correctly anyway.

Not the answer you're looking for? Browse other questions tagged or ask your own question.