Настройка
У меня есть библиотека графов, в которой я пытаюсь максимально разложить вещи, и я нашел самый простой способ описать это следующим образом: существует ванильный тип node
, реализующий только список ребер:
class node
{
public:
int* edges;
int edge_count;
};
Затем я хотел бы добавить интерфейсы ко всему этому миксу, например:
template <class T>
class node_weight
{
public:
T weight;
};
template <class T>
class node_position
{
public:
T x;
T y;
};
и так далее. Затем появляется реальный класс графа, который основан на фактическом типе узла:
template <class node_T>
class graph
{
protected:
node_T* nodes;
public:
static graph cartesian(int n, int m)
{
graph r;
r.nodes = new node_T[n * m];
return r;
}
};
Суть в том, что он назвал конструкторы, которые строят некоторые специальные графы, например, декартову решетку. В этом случае я хотел бы иметь возможность добавлять некоторую дополнительную информацию в график в зависимости от того, какие интерфейсы реализованы node_T
.
Как лучше всего это сделать?
Возможное решение
Я подумал о следующем скромном решении, через dynamic_cast<>
:
template <class node_T, class weight_T, class position_T>
class graph
{
protected:
node_T* nodes;
public:
static graph cartesian(int n, int m)
{
graph r;
r.nodes = new node_T[n * m];
if (dynamic_cast<node_weight<weight_T>>(r.nodes[0]) != nullptr)
{
// do stuff knowing you can add weights
}
if (dynamic_cast<node_position<positionT>>(r.nodes[0]) != nullptr)
{
// do stuff knowing you can set position
}
return r;
}
};
, который будет работать на node_T
, являясь следующим:
template <class weight_T, class position_T>
class node_weight_position :
public node, public node_weight<weight_T>, public node_position<position_T>
{
// ...
};
Вопросы
Это - философски - правильный путь? Я знаю, что люди не очень хорошо смотрят на множественное наследование, хотя с такими "интерфейсами" все должно быть хорошо.
К сожалению, есть проблемы с этим. Из того, что я знаю, по крайней мере, dynamic_cast<>
включает в себя довольно много времени выполнения. Следовательно, я сталкиваюсь с проблемой с тем, что я решил ранее: написание алгоритмов графа, которые требуют весов независимо от того, имеют ли вес действительный класс node_T
или нет. Решение с этим подходом «интерфейса» было бы написать функцию:
template <class node_T, class weight_T>
inline weight_T get_weight(node_T const & n)
{
if (dynamic_cast<node_weight<weight_T>>(n) != nullptr)
{
return dynamic_cast<node_weight<weight_T>>(n).weight;
}
return T(1);
}
но проблема в том, что он работает с использованием информации времени выполнения (dynamic_cast
), но в принципе я хотел бы решить это во время компиляции и, таким образом, сделать код более эффективным.
Если есть другое решение, которое решило бы обе проблемы, особенно более чистое и лучшее, чем у меня, я хотел бы услышать об этом!