views:

73

answers:

1

Okay, so, the idea is that I have a map of "components", which inherit from componentBase, and are keyed on an ID unique to the most-derived*.

Only, I can't think of a good way to get this to work. I tried it with the constructor, but that doesn't work (Maybe I did it wrong). The problem with any virtual, etc, inheritance tricks are that the user has to impliment them at the bottom, which can be forgotten and makes it less... clean.

*Right phrase? If -> is inheritance; foo is most-derived: foo->foo1->foo2->componentBase

Here's some code showing the problem, and why CRTP can't cut it: (No, it's not legit code, but I'm trying to get my thoughts down)

#include<map>

class componentBase
{ public: virtual static char idFunction() = 0; };

template <class T>
class component
    : public virtual componentBase
{
public:
    static char idFunction(){ return reinterpret_cast<char>(&idFunction); }
};

class intermediateDerivations1
    : public virtual component<intermediateDerivations1>
{
};

class intermediateDerivations2
    : public virtual component<intermediateDerivations2>
{   };

class derived1
    : public intermediateDerivations1
{   };

class derived2
    : public intermediateDerivations1
{   };


//How the unique ID gets used (more or less)
std::map<char, componentBase*> TheMap;

template<class T>
void addToMap(componentBase * c)
{
    TheMap[T::idFunction()] = c;
}

template<class T>
T * getFromMap()
{
    return TheMap[T::idFunction()];
}

int main()
{

    //In each case, the key needs to be different.

    //For these, the CRTP should do it:
    getFromMap<intermediateDerivations1>();
    getFromMap<intermediateDerivations2>();

    //But not for these.
    getFromMap<derived1>();
    getFromMap<derived2>();

    return 0;
}

More or less, I need something that is always there, no matter what the user does, and has a sortable value that's unique to the most-derived class.

Also, I realize this isn't the best-asked question, I'm actually having some unexpected difficultly wrapping my head around it in words, so ask questions if/when you need clarification.

Edit: Using Beta's phrasing; The class derived2 has an ID number, unique among all classes derived from ComponentBase, and from which no other classes are derived - except that there should be no usage cases in which we're dealing with an instance when we don't know the most-derived type. That is, we should never have to deal with a foo1* that is actually pointing to a `foo.

Any time that I need to access this ID, I have type information about the most-derived class; via the templated nature of addComponent, getComponent and removeComponent.

Hmm, to put it another way; I need to "convert" type into a unique number while I know the type, so that I can later distinguish between two things when I don't have the type information.

A: 

I don't understand why you are using reinterpret_cast in class component.

As far as having unique IDs, you should have some kind of process to validate that the ID is not used by any derived instance.

On the other hand, each class should implement a static clone or create method. The factory would have a map of . The function pointer points to the specific class' create or clone method. Since the std::map cannot be created as a const static entity during compilation time, I generally use constant static arrays to hold the IDs and function pointers. If the array is small, it is insignificant in performance to a map.

Example:

class Base
{;};

// Declare a synonym for a pointer to the creation function.
typedef Base *    (*P_Creation_Function)(unsigned int id);

struct Creation_Entry
{
    unsigned int         class_id;
    P_Creation_Function  p_creator;
};

class Child1 : public Base
{
  public:
    static Base * create(unsigned int id);
};

Creation_Entry  creation_table[] =
{
    {1, Child1::create},
};

static const unsigned int NUM_CREATORS =
    sizeof(creation_table) / sizeof(creation_table[0]);

//  Process 1:  search table for ID
for (unsigned int i = 0; i < NUM_CREATORS; ++i)
{
    if (creation_table[i].class_id == new_id)
    {
        return (*creation_table[i].p_creator)(new_id);
    }
}

//  Process 2:  Execute each creation function in the table.
//  Creation functions will return NULL if the ID is not a match
Base * p_new_object;
for (unsigned int j = 0; j < NUM_CREATORS; ++j)
{
    p_new_object = (*creation_table[j].p_creator)(new_id);
    if (p_new_object)
    {
        return p_new_object;
    }
}

For small projects, the overhead of a creation function return NULL is not significant compared to other bottlenecks (such as disk i/o). The second process does not require the factory to know the class ID; the class ID remains encapsulated in the class.

I've used both processes and implement them depending on my mood and the project size. :-)

Thomas Matthews
I'm not entirely following what you're saying, but I think you're missing something. First, I don't know what you intend by new_id. Second, it looks like *maybe* you're doing unique IDs per instance, which isn't the problem. Third, it looks like you're requiring the user-code to impliment a given function, the avoidance of which is also part of the problem.
Narfanator