函数
函数设计
建议8.1.1 避免函数过长,函数不超过50行(非空非注释)
函数应该可以一屏显示完 (50行以内),只做一件事情,而且把它做好。
过长的函数往往意味着函数功能不单一,过于复杂,或过分呈现细节,未进行进一步抽象。
例外:某些实现算法的函数,由于算法的聚合性与功能的全面性,可能会超过50行。
即使一个长函数现在工作的非常好, 一旦有人对其修改, 有可能出现新的问题, 甚至导致难以发现的bug。建议将其拆分为更加简短并易于管理的若干函数,以便于他人阅读和修改代码。
内联函数
建议8.2.1 内联函数不超过10行(非空非注释)
说明:内联函数具有一般函数的特性,它与一般函数不同之处只在于函数调用的处理。一般函数进行调用时,要将程序执行权转到被调用函数中,然后再返回到调用它的函数中;而内联函数在调用时,是将调用表达式用内联函数体来替换。
内联函数只适合于只有 1~10 行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,也没有必要用内联函数实现,一般的编译器会放弃内联方式,而采用普通的方式调用函数。
如果内联函数包含复杂的控制结构,如循环、分支(switch)、try-catch 等语句,一般编译器将该函数视同普通函数。虚函数、递归函数不能被用来做内联函数。
函数参数
建议8.3.1 函数参数使用引用取代指针
说明:引用比指针更安全,因为它一定非空,且一定不会再指向其他目标;引用不需要检查非法的NULL指针。
选择 const 避免参数被修改,让代码阅读者清晰地知道该参数不被修改,可大大增强代码可读性。
建议8.3.2 使用强类型参数,避免使用void*
尽管不同的语言对待强类型和弱类型有自己的观点,但是一般认为c/c++是强类型语言,既然我们使用的语言是强类型的,就应该保持这样的风格。好处是尽量让编译器在编译阶段就检查出类型不匹配的问题。
使用强类型便于编译器帮我们发现错误,如下代码中注意函数 FooListAddNode 的使用:
struct FooNode {
struct List link;
int foo;
};
struct BarNode {
struct List link;
int bar;
}
void FooListAddNode(void *node) { // Bad: 这里用 void * 类型传递参数
FooNode *foo = (FooNode *)node;
ListAppend(&fooList, &foo->link);
}
void MakeTheList() {
FooNode *foo = nullptr;
BarNode *bar = nullptr;
...
FooListAddNode(bar); // Wrong: 这里本意是想传递参数 foo,但错传了 bar,却没有报错
}
- 可以使用模板函数来实现参数类型的变化。
- 可以使用基类指针来实现多态。
建议8.3.3 函数的参数个数不超过5个
函数的参数过多,会使得该函数易于受外部变化的影响,从而影响维护工作。函数的参数过多同时也会增大测试的工作量。
如果超过可以考虑:
- 看能否拆分函数
- 看能否将相关参数合在一起,定义结构体