我有一些复杂的继承结构,主要是为了避免代码复制和促进各种类的通用接口。它依赖于虚拟和非虚拟继承,看起来或多或少是这样的:
class AbstractItem
{
//bunch of abstract methods
};
class AbstractNode : virtual public AbstractItem
{
//some more virtual abstract methods
};
class AbstractEdge : virtual public AbstractItem
{
//yet some different virtual abstract methods
};
然后是一些像这样的“真实”类
class Item : virtual public AbstractItem
{
//implements AbstractItem
};
class Node : public Item, public AbstractNode
{
//implements AbstractNode
};
class Edge : public Item, public AbstractEdge
{
//implemetns AbstractEdge
};
并将其打包到图模型类中,以便:
class AbstractGraph
{
virtual QList<AbstractNode*> nodes() const = 0;
virtual QList<AbstractEdge*> edges() const = 0;
};
class GraphModel : public AbstractGraph
{
public:
virtual QList<AbstractNode*> nodes() const override; //this converts m_Nodes to a list of AbstractNode*
virtual QList<AbstractEdge*> edges() const override; //dtto
private:
QList<Node*> m_Nodes;
QList<Edge*> m_Edge;
};
这种错综复杂的结构的原因是有不同的类实现AbstractGraph
,例如排序模型,过滤和那些有不同变体的类 - 有些存储它们的数据就像显示的模型一样,并且有自己的AbstractItem集合/ Node / Edge派生类,其他是动态的,并且依赖于底层图形/模型的数据而没有它们自己的数据。例如:
class FilterNode : public AbstractNode
{
//access the data in the m_Item via AbstractItem interface and implements differently AbstractNode interface
private:
AbstractItem *m_Item = nullptr; //this variable holds pointer to some real item with actual data such as the one from GraphModel
};
class GraphFilter : public AbstractGraph
{
//implements the interface differently to the GraphModel
private:
QList<FilterNode*> m_Nodes;
AbstractGraph *m_Source = nullptr; //source graph...
};
我对此有第二个想法,因为它依赖于(虚拟)继承,依赖于通过base等调用的抽象方法。这样的开销是否显着?
另一种选择是:
a)复制 - 粘贴大量代码以避免虚拟方法和大部分继承,但这将是代码维护的噩梦。加上没有通用接口...
b)模板全部以某种方式......我有点不确定,我不知道它是否可能。我已经在这个地方的几个地方使用它们以避免代码重复。
那么它看起来是否合理或类似矫枉过正?我可以补充一点,在某些情况下,我将直接调用方法(在模型内)绕过虚拟调用,但在外部它几乎总是通过抽象基调用。
答案 0 :(得分:3)
尝试使用动态多态与C ++实现通用图算法
虚函数开销越显着,功能越简单。在引用的界面中,您还可以从各种函数返回容器。即使这些是COW容器,也涉及一些工作,随便访问序列可能很容易取消共享(即复制)表示。
在稍微遥远的过去(大约1990年至1996年),我已经尝试了基于动态多态的图算法的通用实现,并且正在努力解决各种问题以使其工作。当我第一次阅读有关STL的文章时,发现大多数问题可以通过类似的抽象来解决(尽管仍然缺少一个关键思想:属性映射;有关详细信息,请参阅下面对BGL的引用)。
我发现在类似STL的抽象方面实现图算法更为可取。算法是根据特定的概念实现的功能模板,除了两个主要区别外,它们有点像基类:
不可否认,我有偏见,因为我在这个主题上写了diploma thesis。对于这种方法的[独立开发]应用,请查看Boost Graph Library (BGL)。
对于比较不同函数调用方法的一些性能测量,请查看function call benchmarks。它们是在Performance TR的函数调用的性能测量之后建模的。