【发布时间】:2011-11-18 01:03:46
【问题描述】:
设置
我有一个图形库,我试图在其中尽可能多地分解事物,我发现的最简洁的描述方式如下:有一个香草类型 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) 工作,但原则上我想在编译时决定它,从而使代码更有效率。
如果有一个不同的解决方案可以解决这两个问题,尤其是比我现有的更清洁、更好的解决方案,我很想听听!
【问题讨论】:
-
天哪。按值返回的构造函数?原始指针?具有指针成员且没有复制构造函数的类?我认为您可能应该从更简单的东西开始并逐渐建立它......
-
请评论手头的问题,而不是演示文稿中的选择:)。我写它是为了便于理解;实际上有一个 std::vector 而不是指针,事情不是公开的,等等。
-
关于 CRTP: 没有帮助,
dynamic_cast用于检查是否实际实现了特定接口。问题是node_T类型在编译时为编译器所知,因此应该有一种方法可以使用该知识并根据实际类型改变函数的行为。 -
@fledgeling:有几个不连贯的小事情至少会引起人们的注意,所以很难简明扼要地说除了“更仔细地设计它”之外应该做什么。也许如果你把它分解成更小的部分,它们可以一一简洁地回答。不管怎样,你似乎已经得到了你想要的东西,所以祝你好运!
标签: c++ templates multiple-inheritance named-constructor