設定
私は可能な限り物事を分解しようとしているグラフライブラリを持っています、そして私が見つけたそれを説明する最もきれいな方法は次のとおりです: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
)を使用して機能することです。それでも、原則として、コンパイル時に決定して、コードをより効率的にしたいと思います。
両方の問題を解決する別の解決策、特に私が持っているものよりもクリーンで優れた解決策がある場合は、それについて聞いてみたいです!