首页 \ 问答 \ C ++函数/方法设计的良好实践(Good practice in C++ function/method design)

C ++函数/方法设计的良好实践(Good practice in C++ function/method design)

我对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或者仅仅是void?


I have a confusion about C++ function/method design as below:

1.

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

    void addTwoNumbers();
};

2.

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

In 1., one can basically declare a class variable and the void addTwoNumbers() will just implement it and assign to the class variable (sum_). I found using 1. is cleaner but using 2. looks like it more intuitive for function use.

Which one is actually best option considering the function/method is not restricted to only this basic addition functionality -- I mean in general how to decide to use with return or simply void?


原文:https://stackoverflow.com/questions/47420381
更新时间:2019-07-15 05:16

最满意答案

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

只要可能,重新进入就是选择无状态函数的一个重要原因。 但是,在保持状态变得更经济的情况下 - 例如,当您使用Builder Design Pattern时

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

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

您的代码的人类阅读者读取使用带有参数传递的函数调用的调用比读取三部分的调用 - 获取结果序列更容易。

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

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


The major difference between the two functions is that the second one is stateless*, while the first one has a state. Other things being equal, stateless approach is preferred, because it gives the users of your class more flexibility at utilizing your class in their systems. For example, stateless functions are re-entrant, while functions that rely on state may require the code that uses them to take additional measures that prevent incorrect use.

Re-entrancy alone is a big reason to prefer stateless functions whenever possible. However, there are situations when keeping state becomes more economical - for example, when you are using Builder Design Pattern.

Another important advantage of keeping your functions stateless whenever it is possible is that the call sequence becomes more readable. A call of a method that relies on the state consists of these parts:

  • Set up the object before the call
  • Make the call
  • Harvest the result of the call (optional)

Human readers of your code will have much easier time reading the call that uses a function invocation with parameter passing than the three-part setup-call-get result sequence.

There are situations when you have to have state, for example, when you want to defer the action. In this case the parameters are supplied by one part of the code, while the computation is initiated by some other part of the code. In terms of your example, one function would call set_num1 and set_num2, while another function would call addTwoNumbers at some later time. In situations like this you could save the parameters on the object itself, or create a separate object with deferred parameters.

* This is only an assumption based on the signature of your member function. Your second function gets all the data that it needs as parameters, and returns the value to the caller; Obviously, implementations may choose to add some state, e.g. by saving the last result, but that is uncommon for addTwoNumbers functions, so I assume that your code does not do it.

2017-11-21

相关问答

更多

将对象数组分配给DataGrid(Assigning an array of objects to a DataGrid)

这是你的答案 &t;?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="initialize()"> <mx:Script> <![CDATA[ import mx.collections.HierarchicalData; var a:Array = n

根据对象的属性值对对象进行分组(group objects based on their attribute values)

请尝试以下方法。 function groupBy($array, $key) { $groupedData = []; foreach ($array as $value) { if ( ! array_key_exists($value[$key], $groupedData)) { $groupedData[$value[$key]] = []; } $groupedData[$value[$key]]

D语言:返回新创建的关联数组(D language: Return freshly created associative array)

您可以使用 return (int[char]).init; 所以你不必申报。 所有类型的init属性表示该类型的默认初始化值(引用为null,空动态数组和空关联数组,具有当前实现) you can use return (int[char]).init; so you don't have to declare it. the init property on all type denotes the default initialization value for the type (n

当使用`:key`时,Common Lisp中的#'adjoin是否按照HyperSpec工作?(Does #'adjoin in Common Lisp work as per HyperSpec when used with `:key`?)

这是HyperSpec中的一个错误, 问题ADJOIN-SPECIFICATION已在CLiki上写过。 相关部分是: 问题描述: CLHS通过引用第17.2.1节“满足双参数测试”来指定存在于:KEY参数的ADJOIN行为。 这是不正确的,因为第17.2.1节指定不在ITEM参数上调用键函数,而ADJOIN则在pushnew中指定。 提案(ADJOIN:澄清): 更换: test,test-not和key会影响如何确定item是否与list的元素相同。 有关详细信息,请参见第17.2.1节(满

在nginx上强制HTTPS,但有异常(Forcing HTTPS on nginx with exceptions)

使用两个服务器块,一个用于安全,一个用于不安全连接。 server { listen 80; location / { return 301 https://$host$request_uri; } location /some/url { ... } ... include /path/to/common/config; } server { listen 443 ssl; ...

单击加载事件上的按钮(Click button on load event)

<body onload='onLoad(); fan();'>... 但是最好避免内联JS,你最好开始研究集中式事件管理。 这有各种优点。 我昨天写的另一个问题的答案概述了为什么会这样。 像jQuery这样的东西如果它对你来说是新的那么简单。 $(function() { $('body').on('load', function() { onLoad(); fan(); }); }); <body onload='onLoad(); fan

在一列中检索满足其他列中条件组合的所有不同值(SQL)(Retrieve all distinct values in one column that satisfies combination of condition in other column (SQL))

我用这个方法来处理这个问题having 如果你想要1和2以及其他任何东西: select x from t where y in (1, 2) group by x having count(distinct y) = 2; 如果你知道x / y对是唯一的,那么distinct将是不必要的。 如果你只想要1 ,因为这完全匹配: select x from t group by x having sum(case when y = 1 then 1 else 0 end) > 0 and

为什么调试器会说“class name = ...”而不是内存位置?(Why does debugger say “class name = …” instead of memory location?)

调试器调用description方法来打印其日志。 我会检查是否在违规类中覆盖了该方法。 例如 - (NSString *)description { return [NSString stringWithFormat:@"test class description"]; } 如果我在调试器中PO这个类的实例,它会吐出“测试类描述”而不是内存地址 The debugger calls the description method to print its log. I would

相关文章

更多

最新问答

更多
  • asp.net任意用户信息(asp.net arbitrary user info)
  • 如何使用python计算docx文件中表中行的值(How to count the row's values in tables in docx file by using python)
  • MySQL:用户访问和数据库覆盖(MySQL: User access and DB overwriting)
  • 还有另一种“使用未分配的局部变量”的问题(Yet Another “Use of unassigned local variable 'whatever' ” question)
  • 开源证书颁发机构软件(Open source certificate authority software)
  • Rails中的迭代form_for是在create上添加模型的所有实例(Iteration in Rails form_for is adding all instances of model on create)
  • 如何扩展我的表视图单元格?(How to expand my table view cell?)
  • 如何使用SPARQL区分Thing和无生命对象(How to differentiate between a Thing and an inanimate object with SPARQL)
  • 在IdentityServer中,Client Secrets和Scope Secrets有什么区别?(In IdentityServer, what is the difference between Client Secrets and Scope Secrets?)
  • 如何在具有附加类时重写类(How do I override a class when it has a attached class)
  • 如何使用Git在Azure上部署C#,MVC4应用程序(How to deploy a C#, MVC4 application on Azure using Git)
  • Sitecore 7内容搜索爬网程序根目录之外的索引项(Sitecore 7 Content Search indexing items outside of crawler root)
  • 我应该在线课程使用utf-8编码吗?(Should I use utf-8 encoding for an online course?)
  • 如何在Cucumber-JS步骤定义中使用Node-mysql连接到MySQL?(How to connect to MySQL using Node-mysql in a Cucumber-JS step definition?)
  • 在MVC 4中的google.maps.LatLng(lat,lon)中将JSON字符串值分配给纬度和经度(Assign the JSON string value to Latitude and Longitude in google.maps.LatLng(lat,lon) in MVC 4)
  • awk:通过特定的分隔符删除字符串(awk: remove strings by specific delimiter)
  • 如何测试Vista的应用程序(How to test app for Vista)
  • Elasticsearch聚合器 - 缺失值的工作原理(Elasticsearch aggregators - How missing values work)
  • 绘制datetime.date熊猫(Plot datetime.date pandas)
  • PostgreSQL作为WSO2 EI和APIM + IS的数据源(PostgreSQL as datasource for WSO2 EI and APIM+IS)
  • 如何使用bash在postgres中运行alter table脚本(How to run alter table script in postgres using bash)
  • 可能使用PHP阻止整个美国州访问我的网站?(Might it be possible to block an entire US state from accessing my site, using PHP?)
  • restangular删除并输入错误网:: ERR_NAME_NOT_RESOLVED(restangular remove and put error net::ERR_NAME_NOT_RESOLVED)
  • 常见问题解答的Modx(Revolution)搜索功能(Modx(Revolution) search function for FAQs)
  • Rubymine如何使用远程口译员和Git?(How Does Rubymine Work With Remote Interpreters and Git?)
  • prepareForSegue和PerformSegueWithIdentifier发件人(prepareForSegue and PerformSegueWithIdentifier sender)
  • postgrsql与PowerShell无提示安装问题(postgresql silent installation issue with powershell)
  • 比较两个greps的输出(Comparing output from two greps)
  • 使用.NET RIA Data Services删除Silverlight 3中的数据(Deleting data in Silverlight 3 with .NET RIA Data Services)
  • 此行中AND运算符的含义(meaning of the AND operator in this line)