2010-08-19 4 views
1

Я пытаюсь написать функцию для класса базы данных, которая в основном представляет собой оболочку вокруг hash_map объектов (например, фигур), индексированных идентификационными номерами, которые будут искать идентификатор и передавать его соответствующему типу указателя.Можно ли взять тип в качестве аргумента в функции?

например. Я хотел бы быть в состоянии сделать что-то вроде этого:

Circle* shapeToLookup = NULL; 
int idNum = 12; 
database.lookup(idNum, circleToLookup); 
if(circleToLookup != NULL) 
{ 
    // Do stuff with the circle. 
} 

и есть база данных о типе аргумента. Есть ли способ сделать это без перегрузки функции (lookup(int, Circle*), lookup(int, Rect*), ad nauseum)? Можете ли вы объявить такую ​​функцию, как lookup(int, Shape*), и знать, какой тип она дана?

Спасибо!

+0

ИМО, это вопрос базы данных. Вы также не говорите, что такое БД. Я бы посмотрел ключевое слово SQL «LIKE». – JustBoo

+0

Как вы планируете передавать информацию о типе в базу данных? (или я должен сказать, как это получит база данных?) –

+0

Если вы хотите, чтобы база данных * что-то делала * с этой информацией, вам нужно будет написать некоторый код для конкретного круга, некоторый код для конкретного прямоугольника и т. д. ad nauseam. Вопрос: * где * вы хотите поместить этот код. Можете ли вы рассказать нам, что вы хотите сделать в базе данных? – Beta

ответ

3

Вы можете сделать это с помощью шаблона.

Редактировать: новая реализация основана на дополнительной информации. Если mymap является std::map<int, Shape*>:

template <typename T> 
void lookup(int idNum, T* &ptr) { 
    auto it = mymap.find(idNum); 
    if (it == mymap.end()) { 
     ptr = 0; 
    } else { 
     ptr = dynamic_cast<T*>(*it); // Shape must have a virtual member function 
    } 
} 

Или вы можете предпочесть:

template <typename T> 
T* lookup(int idNum) { 
    auto it = mymap.find(idNum); 
    if (it == mymap.end()) { 
     return 0; 
    } 
    return dynamic_cast<T*>(*it); 
} 

Затем вызовите его, как Circle *circle = database.lookup<Circle>(123);

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

старой реализации, когда я думал, что DB может хранить копии POD:

template <typename T> 
void lookup(int idNum, T* &ptr) { 
    void *theresult = // something based on idNum 

    // some check needed here that theresult really is the right type. 
    // how you do this depends on the database, but suppose that 
    // the database gives us some integer "type" which indicates the type 
    if (type != type_constant<T>::value) { 
     ptr = 0; 
    } else { 
     ptr = static_cast<T*>(theresult); 
    } 
} 

type_constant является примером "черт типа" вы реализуете это нравится:

template <typename T> 
struct type_constant {}; 

template <> 
struct type_constant<Circle> { 
    static const int value = 1; 
}; 

template <> 
struct type_constant<Rectangle> { 
    static const int value = 2; 
}; 

// etc... 
+0

Не следует использовать dynamic_cast <> для приведения к типам детей. (т. е. от Shape * до Circle *)? –

+0

Может быть. Я не знаю, что эта база данных действительно возвращает - если это 'Shape *', чей referand является подклассом, а если 'Shape *' имеет какие-либо виртуальные функции-члены, то да. Если сама база данных не основана на объекте, или кто-то где-то должен что-то делать, основываясь на записи, указывающей тип. Я не могу сказать из вопроса, является ли «Shape *» фактическим базовым классом или просто тем, о чем упоминал вопросник, думая, что он может быть частью решения. –

+0

Я не знал о 'type_constant', и я, скорее всего, просто посмотрю на' dynamic_cast', как упоминал Мартин. Немного о грандиозном шаблоне для того, чтобы не думать шаблоны сразу. – spbots

0

Другие объяснили, как передать тип функции (используя шаблоны функций). Я хотел бы дать другую точку зрения:

Это может быть еще лучше ввести новую виртуальную функцию Shape, а затем переместить Do stuff with the Circle части в переопределение этой виртуальной функции в Cricle классе.

Таким образом, вы удаляете необходимость знать тип. Вы просто получаете объект Shape из своей базы данных, а затем вызываете функцию doStuff() - и она делает правильную вещь в зависимости от фактического типа Shape. Хороший вариант использования для виртуальной функции. :-)

Конечно, это может быть более или менее просто, в зависимости от того, что на самом деле делает Do stuff.

+0

К сожалению, это основное задание рефакторинга по унаследованному коду, где «фигуры» все сильно зависят друг от друга, поэтому поиск происходит в других формах, а doStuff() не обязательно является общей функциональностью. Спасибо, хотя :) – spbots

4
template <T> 
Database::lookup(int idNum, T TobjectToLookup) 
{ 
    // inside here, T is the type of the object passed in/ 
} 
Смежные вопросы