Language agnostic 虚拟函数调用的圈复杂度是(或应该是)什么?

Language agnostic 虚拟函数调用的圈复杂度是(或应该是)什么?,language-agnostic,switch-statement,virtual-functions,code-metrics,cyclomatic-complexity,Language Agnostic,Switch Statement,Virtual Functions,Code Metrics,Cyclomatic Complexity,提供一个粗略的度量标准,说明理解给定函数有多困难,或者它包含bug的可能性有多大。在我读过的实现中,通常所有基本的控制流构造(if、case、while、for等)都会将函数的复杂性增加1。在我看来,圈复杂度旨在确定“通过程序源代码的线性独立路径的数量”,虚拟函数调用也会增加函数的圈复杂度,因为在运行时调用哪个实现的模糊性(调用在执行路径中创建另一个分支) 但是,如果函数包含等效的switch语句,则对该函数的惩罚量与对该函数的惩罚量相同(每个“case”关键字对应一个点,实现该虚拟函数的层次结

提供一个粗略的度量标准,说明理解给定函数有多困难,或者它包含bug的可能性有多大。在我读过的实现中,通常所有基本的控制流构造(if、case、while、for等)都会将函数的复杂性增加1。在我看来,圈复杂度旨在确定“通过程序源代码的线性独立路径的数量”,虚拟函数调用也会增加函数的圈复杂度,因为在运行时调用哪个实现的模糊性(调用在执行路径中创建另一个分支)

但是,如果函数包含等效的switch语句,则对该函数的惩罚量与对该函数的惩罚量相同(每个“case”关键字对应一个点,实现该虚拟函数的层次结构中的每个类对应一个case关键字)感觉过于苛刻,因为虚拟函数调用通常被认为是更好的编程实践

一个虚拟函数调用的圈复杂度代价应该是多少?我不确定我的推理是反对圈复杂度作为度量的效用,还是反对使用虚拟函数或其他东西


编辑:在人们的反应之后,我意识到它不应该增加圈复杂度,因为我们可以将虚函数调用等效于对包含大量开关语句的全局函数的调用。即使该函数将得到坏的分数,它只在程序中存在一次,而替换每个虚拟函数。直接使用switch语句调用将导致多次开销。

圈复杂度通常不适用于函数调用边界,而是函数内部的度量。因此,虚拟调用的计数不超过非虚拟的静态函数调用。

虚拟函数调用不会增加圈复杂度,因为“将调用哪个实现的模糊性[over]”在函数调用之外。一旦设置了对象值,就没有模糊性。我们确切地知道将调用什么方法

BaseClass baseObj = null;
// this part has multiple paths & add to CC
if (x == y)
     baseObj = new Derived1();
else
     baseObj = new Derived2();

// this part has one path and does not add to the CC
baseObj.virtualMethod1();
baseObj.virtualMethod2();
baseObj.virtualMethod3();

我不太喜欢圈复杂度,但在本例中,您调用的是一个函数。它将做大致相同的事情(除非类层次结构设计真的搞砸了)事实是,如果你调用任何函数,你可以得到一些不同的行为,这取决于你传入的参数,而这不计入CC

因此,我会完全忽略这一成本

虚拟函数调用应该增加 a的圈复杂度 由于 不明确的是,哪些实施将 在运行时被调用


啊,但它在运行时并不含糊(除非你在做元编程/猴子补丁);它完全由接收器的类型/类别决定。

“它将做大致相同的事情(除非类层次结构设计真的搞砸了),根据调用它的情况会有一些变化。”-Barbara Liskov,1987年。IMO您的问题指出了“全球复杂性”与“局部复杂性”之间差异的一个很好的例子,后者主要衡量理解程序的难度,这基本上衡量了为所有定义的方法编写测试覆盖率的难度。随着软件项目的发展,我预计这些复杂度的概念将趋于收敛,但对于小的代码库,我认为可以公平地说,基于圈复杂度等度量的最佳实践偏向于“全局复杂度”回想起来,我认为这个问题的答案是,它应该比开关语句更坏,而不是更好,因为当你考虑孤立模块中的多态调用时,它实际上是一个无界开关(你不知道派生类可能是什么)。从整个程序知识的角度来看,它应该被视为一个开关。只是因为我们认为它们在这个度量中是等价的,并不意味着你不能根据其他度量来评估代码的质量(比如需要改变的行数,以获得期望的效果,多态性获胜)。