2010-03-17 2 views
2

Итак, идея состоит в том, что у меня есть карта «компонентов», которая наследуется от componentBase и вводится в идентификатор, уникальный для самого производного * ,Уникальный идентификатор, определяемый большинством производных классов, доступный через базовый класс

Только я не могу придумать хороший способ заставить это работать. Я попробовал его с конструктором, но это не работает (возможно, я сделал это неправильно). Проблема с любыми виртуальными и т. Д. Трюками наследования заключается в том, что пользователь должен внедрить их внизу, что можно забыть и сделать его менее ... чистым.

* Правильная фраза? Если -> - наследование; foo является самым производным: foo-> foo1-> foo2-> componentBase

Вот несколько примеров, показывающих проблему, и почему CRTP не может ее обрезать: (Нет, это не законный код, но я пытаюсь чтобы мои мысли вниз)

#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; 
} 

Более или менее, мне нужно что-то, что всегда есть, независимо от того, что делает пользователь, и имеет Сортируемое значение, уникальные для наиболее производного класса.

Кроме того, я понимаю, что это не самый лучший вопрос, я на самом деле неожиданно затрудняюсь обмануть его в словах, поэтому задавайте вопросы, если/когда вам нужно разъяснение.

Редактировать: Использование фразы Бета; Класс имеет номер идентификатора, уникальный среди всех классов, полученных из ComponentBase, и из которых не выведены никакие другие классы, за исключением того, что не должно быть случаев использования, в которых мы имеем дело с экземпляром, когда мы не знаем самый производный тип. То есть нам никогда не придется иметь дело с foo1*, который фактически указывает на `` foo`.

В любое время, когда мне нужно получить доступ к этому ID, у меня есть информация о самом производном классе; через шаблонный характер addComponent, getComponent и removeComponent.

Хм, другими словами; Мне нужно «преобразовать» тип в уникальный номер, в то время как я знаю тип, так что я могу позже различать две вещи, когда у нет есть информация о типе.

+0

Вы уже задавали подобные вопросы. Как это отличается? – Tronic

+0

Вы имеете в виду, что каждый экземпляр производного2 имеет идентификационный номер, уникальный среди всех экземпляров ComponentBase? Или что класс производный2 имеет идентификационный номер, уникальный среди всех классов, полученных из ComponentBase? Или среди всех классов, полученных из ComponentBase * и из которых не выведены никакие другие классы *? – Beta

+0

@Tronic: Предыдущие вопросы не касались наследования; как таковой, можно было легко гарантировать idFunction(), который соответствовал ограничениям, поскольку для его реализации не было никакой зависимости от программиста-пользователя. – Narfanator

ответ

0

Я не понимаю, почему вы используете reinterpret_cast в class component.

Что касается уникальных идентификаторов, у вас должен быть какой-то процесс проверки того, что идентификатор не используется никаким производным экземпляром.

С другой стороны, каждый класс должен применять статический метод clone или create. Завод имел бы map оф. Указатель функции указывает на метод класса create или clone. Поскольку std::map не может быть создан как const-объект во время компиляции, я обычно использую постоянные статические массивы для хранения идентификаторов и указателей функций. Если массив мал, он невелик по производительности до map.

Пример:

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; 
    } 
} 

Для небольших проектов, накладные расходы на создание функции возврата NULL не являются существенными по сравнению с другими узкими местами (например, диска I/O).Второй процесс не требует, чтобы фабрика знала идентификатор класса; идентификатор класса остается инкапсулированным в классе.

Я использовал оба процесса и реализовал их в зависимости от моего настроения и размера проекта. :-)

+0

Я не совсем понимаю, что вы говорите, но я думаю, что вы что-то упустили. Во-первых, я не знаю, что вы намерены new_id. Во-вторых, это выглядит так: возможно, вы делаете уникальные идентификаторы на один экземпляр, что не является проблемой. В-третьих, похоже, что вам требуется, чтобы пользовательский код вводил определенную функцию, избегание которой также является частью проблемы. – Narfanator

0

Вы можете использовать оператор typeid.

Если у вас есть ComponentBase * компонент, то

typeid(*component) 

возвратит type_info & объект, который однозначно идентифицирует класс объекта, составляющие указатель указывает на. (Если компонент указывает на объект Derived, то он вернет объект type_info, принадлежащий классу Derived. Обратите внимание, что этот тип (компонент) должен возвращать type_info &, который представляет тип ComponentBase *, поэтому разыменование указателя важно .)

Тогда вы можете использовать, например. адрес этого объекта type_info или результат type_info :: name() в качестве ключа для вашей карты.

Смежные вопросы