C ++函数/方法设计的良好实践

时间:2017-11-21 18:40:01

标签: c++ function

我对C ++函数/方法设计感到困惑,如下所示:

1

class ArithmeticCalculation
{ 
private:
    float num1_;
    float num2_;
    float sum_;

    void addTwoNumbers();
};

2

class ArithmeticCalculation
{ 
private:
    float addTwoNumbers(float num1, float num2);
};

在1.中,一个人基本上可以声明一个类变量,而void addTwoNumbers()只会实现它并分配给类变量(sum_)。我发现使用1.更干净但使用2.看起来它更直观的功能使用。

考虑到函数/方法并不仅限于这个基本的附加功能,哪一个实际上是最佳选择 - 我的意思是一般如何决定使用return还是简单地无效?

3 个答案:

答案 0 :(得分:3)

两个函数之间的主要区别在于第二个函数是无状态 * ,而第一个函数具有状态。在其他条件相同的情况下,首选的是无状态方法,因为它可以让您的班级用户在系统中更灵活地使用您的课程。例如,无状态函数是可重入的,而依赖于状态的函数可能需要使用它们的代码采取其他措施来防止错误使用。

单独重新入侵是尽可能选择无状态功能的重要原因。但是,有些情况下保持状态变得更加经济 - 例如,当您使用Builder Design Pattern时。

在可能的情况下保持函数无状态的另一个重要优点是调用序列变得更易读。依赖于状态的方法的调用由以下部分组成:

  • 在通话前设置对象
  • 拨打电话
  • 收集通话结果(可选)

您的代码的人类读者将更容易阅读使用参数传递的函数调用的调用,而不是三部分的setup-call-get结果序列。

在某些情况下,您必须拥有状态,例如,当您想要推迟操作时。在这种情况下,参数由代码的一部分提供,而计算由代码的其他部分启动。就您的示例而言,一个函数会调用set_num1set_num2,而另一个函数会稍后调用addTwoNumbers。在这种情况下,您可以将参数保存在对象本身上,或者使用延迟参数创建单独的对象。

* 这只是基于成员函数签名的假设。你的第二个函数获取它需要的所有数据作为参数,并将值返回给调用者;显然,实现可以选择添加一些状态,例如通过保存最后的结果,但这对于addTwoNumbers函数来说并不常见,所以我假设您的代码没有这样做。

答案 1 :(得分:2)

第一个功能并没有多大意义。 什么号码?结果在哪里?该名称并未描述预期的副作用,也未描述相关数字的来源。

第二个功能可以清楚地了解发生了什么,结果在哪里,以及如何使用该功能。

您的功能应努力根据功能签名传达其意图。如果这还不够,您需要添加评论或文档,但没有任何评论或文档可以为误导或混淆的签名铺平道路。

考虑一下你的职责是什么,以及命名事物时的期望。例如:

void whatever(const int);

该功能有什么作用?您是否可以在不查看代码或文档的情况下猜测?

与给出更有意义的名称的相同函数进行比较:

void detonateReactor(const int countdownTimeInSeconds);

现在看起来很清楚,以及它会产生什么样的副作用。

答案 2 :(得分:0)

对于第一个选项,您可能已经考虑过这样的事情:

struct Adder {
    float sum;
    float a;
    float b;
    void addNumbers(){ sum = a+b; }
};

可以像这样使用:

Adder adder;
adder.a = 1.0;
adder.b = 2.0;
adder.addNumbers();
std::cout << adder.sum << "\n";

当你真正想要这样做时,没有一个好的论据可以做到:

float addTwoNumbers(float a,float b) { return a+b; }

std::cout << addTwoNumbers(1.0,2.0) << "\n";

并非一切都必须在课堂内。实际上并非所有都应该在一个类中(C ++不是Java)。如果你需要一个添加两个数字的函数,那么写一个函数来添加两个数字并且不要过度思考它。