C/C++;:使用适配器模式是否会导致性能损失? 我在C++项目中使用C语言编写。它提供了一个structstinger(图形数据结构)和如下操作 int stinger_insert_edge_pair (struct stinger *G, int64_t type, int64_t from, int64_t to, double weight, int64_t timestamp) { .... }

C/C++;:使用适配器模式是否会导致性能损失? 我在C++项目中使用C语言编写。它提供了一个structstinger(图形数据结构)和如下操作 int stinger_insert_edge_pair (struct stinger *G, int64_t type, int64_t from, int64_t to, double weight, int64_t timestamp) { .... },c++,oop,design-patterns,adapter,C++,Oop,Design Patterns,Adapter,然而,大多数时候,我不想指定时间戳、权重或类型。默认参数会很好。另外,一个类似OOP的界面也不错:G->insertEdge(u,v)而不是insert_-edge_对(G,u,v,…) 所以我想创建一个适配器类 class Graph { protected: stinger* stingerG; public: /** default parameters ***/ double defaultEdgeWeight = 1.0; /** meth

然而,大多数时候,我不想指定时间戳、权重或类型。默认参数会很好。另外,一个类似OOP的界面也不错:
G->insertEdge(u,v)
而不是
insert_-edge_对(G,u,v,…)

所以我想创建一个适配器

class Graph {

protected:

    stinger* stingerG;

public:

    /** default parameters ***/

    double defaultEdgeWeight = 1.0;


    /** methods **/

    Graph(stinger* stingerG);

     virtual void insertEdge(node u, node v, double weight=defaultEdgeWeight);

   };
方法
insertEdge(…)
只需使用适当的参数调用
stinger\u insert\u edge\u对(this->stinger,…)


然而,性能是这里的一个关键方面。使用这样的适配器类会带来什么样的性能损失?与使用“裸体”库相比,我是否应该期望性能降低?

虚拟函数通常无法内联,因此函数调用的开销相同(在堆栈上推送参数、可能中断管道和缓存等)。在实践中,例行函数调用是非常快的——按时钟周期的顺序。确定这是否合适的唯一方法是在您自己的应用程序上进行测试。

如果您使用普通的
内联
方法,编译器应该在调用时内联这些方法,所以不会有任何性能损失。但是,请注意,您不应该为此使用虚拟函数。

如果您的InserteDE只是将调用转发给stinger\u insert\u edge\u对,那么(很可能)对stinger\u insert\u edge\u对的普通调用和g->insertEdge(如果您删除虚拟说明符)之间生成的代码没有差异。 比较通过普通调用和适配器调用生成的汇编代码,可以公平地输入适配器带来的开销


insertEdge必须是虚拟的吗?您是否计划创建Graph的子类?但是,与函数执行本身的实际成本相比,虚拟函数调用的成本几乎可以忽略不计。

如果不分析,很难判断。除此之外,好的编码的一般方面仍然存在。“除此之外,好的编码的一般方面仍然存在。”在你看来,使用这样的适配器是好的编码吗?为什么要适应虚拟功能?您想提供不同类型的适配器吗?在内联方法中转发对c api的调用的简单适配器应该具有几乎相同的开销。为特定场景使用特定的设计模式是一个设计问题,您能否证实使用特定模式而不是其他模式的原因?性能问题将在后面提出。我认为这样一个类将提供我想要的更简洁、更面向对象的接口,并允许我提供默认参数(是否称之为“适配器模式”)。因此,当需要性能时,您会建议将方法设为非虚拟方法吗?这将启用内联,但如果我理解正确,则非虚拟函数调用的开销不会很大。@cls是的,除非被迫这样做,否则不要使用虚拟函数。几乎总是有编译时的变通方法。如果编译器可以静态地(即在编译时)确定调用函数的类型,则即使虚拟函数也可以内联。注意,我并不是说这是常见的或预期的,只是说这是可能的。你能定义“平凡的内联方法”吗?问题是,至少gcc可能不是真正的内联函数,即使它标记为
inline
。请参阅:另外,gcc还有一个
总是内联的
,但这是非标准功能。在这种情况下,性能比扩展性更重要,因此
insertEdge
不必是虚拟的。如果您太怀疑,我建议您删除它。但我宁愿删除它,因为我知道我永远不会派生和重写,也不会将性能作为理由。