“get() const” 与“getAsConst() const”相比
有人告诉我他们团队中 C++ 风格的差异。 我对这个主题有自己的观点,但我会对每个人的优点和缺点感兴趣。
因此,如果您有一个类属性,您想通过两个 getter 来公开,一个是读/写的,另一个是只读的(即没有 set 方法)。 至少有两种方法可以实现:
class T ;
class MethodA
{
public :
const T & get() const ;
T & get() ;
// etc.
} ;
class MethodB
{
public :
const T & getAsConst() const ;
T & get() ;
// etc.
} ;
每种方法的优点和缺点是什么?
我对 C++ 技术/语义原因更感兴趣,但风格原因也很受欢迎。
请注意,MethodB
有一个主要的技术缺陷(提示:在通用代码中)。
Someone told me about a C++ style difference in their team. I have my own viewpoint on the subject, but I would be interested by pros and cons coming from everyone.
So, in case you have a class property you want to expose via two getters, one read/write, and the other, readonly (i.e. there is no set method). There are at least two ways of doing it:
class T ;
class MethodA
{
public :
const T & get() const ;
T & get() ;
// etc.
} ;
class MethodB
{
public :
const T & getAsConst() const ;
T & get() ;
// etc.
} ;
What would be the pros and the cons of each method?
I am interested more by C++ technical/semantic reasons, but style reasons are welcome, too.
Note that MethodB
has one major technical drawback (hint: in generic code).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
C++ 应该能够在几乎所有情况下完美地应对方法 A。 我一直用它,从来没有遇到过问题。
在我看来,方法B违反了OnceAndOnlyOnce。 而且,现在您需要弄清楚是否正在处理 const 引用来编写第一次编译的代码。
我想这是一种风格问题——从技术上讲,它们都有效,但 MethodA 使编译器工作得更加困难。 对我来说,这是一件好事。
C++ should be perfectly capable to cope with method A in almost all situations. I always use it, and I never had a problem.
Method B is, in my opinion, a case of violation of OnceAndOnlyOnce. And, now you need to go figure out whether you're dealing with const reference to write the code that compiles first time.
I guess this is a stylistic thing - technically they both works, but MethodA makes the compiler to work a bit harder. To me, it's a good thing.
嗯,一方面,当“this”指针为 const 时,必须调用 getAsConst,而不是当您想要接收 const 对象时。 因此,与其他问题一样,它的命名也被巧妙地错误了。 (当 'this' 是非常量时,您仍然可以调用它,但 'this' 既不在这里也不在那里。)
忽略这一点, getAsConst 不会为您带来任何好处,并且会给使用该接口的开发人员带来过度的负担。 现在他必须确定他当前是否正在使用 const 变量,以及他获取的新对象是否需要为 const,而不是仅仅调用“get”并知道他正在获取所需的内容。 之后,如果两个对象由于某些重构而变得非常量,他就必须关闭他的调用。
Well, for one thing, getAsConst must be called when the 'this' pointer is const -- not when you want to receive a const object. So, alongside any other issues, it's subtly misnamed. (You can still call it when 'this' is non-const, but that's neither here nor there.)
Ignoring that, getAsConst earns you nothing, and puts an undue burden on the developer using the interface. Instead of just calling "get" and knowing he's getting what he needs, now he has to ascertain whether or not he's currently using a const variable, and if the new object he's grabbing needs to be const. And later, if both objects become non-const due to some refactoring, he's got to switch out his call.
就我个人而言,我更喜欢第一种方法,因为它可以使界面更加一致。 另外,对我来说 getAsConst() 听起来和 getAsInt() 一样愚蠢。
另一方面,在返回非常量引用或指向类的数据成员的非常量指针之前,您确实应该三思而后行。 这是邀请人们利用你们班级的内部运作,最好是隐藏起来。 换句话说,它破坏了封装。 我会使用 get() const 和 set(),并且仅在没有其他方法或确实有意义时才返回非常量引用,例如提供对数组元素的读/写访问权限或矩阵。
Personally, I prefer the first method, because it makes for a more consistent interface. Also, to me getAsConst() sounds just about as silly as getAsInt().
On a different note, you really should think twice before returning a non-const reference or a non-const pointer to a data member of your class. This is an invitation for people to exploit the inner workings of your class, which ideally should be hidden. In other words it breaks encapsulation. I would use a get() const and a set(), and return a non-const reference only if there is no other way, or when it really makes sense, such as to give read/write access to an element of an array or a matrix.
鉴于标准库设置的样式先例(即 begin() 和 begin() const 仅举一个示例),很明显方法 A 是正确的选择。 我怀疑选择方法B的人是否理智。
Given the style precedent set by the standard library (ie begin() and begin() const to name just one example), it should be obvious that method A is the correct choice. I question the person's sanity that chooses method B.
因此,通常首选第一种样式。
不过,在我当前正在处理的代码库中,我们确实使用了第二种样式的变体,因为我们希望在 const 和非常量用法之间有很大的区别。
在我的具体示例中,我们有 getTessellation 和 getMutableTessellation。 它是通过写时复制指针实现的。 出于性能原因,我们希望尽可能使用 const 版本,因此我们使名称更短,并使用不同的名称,这样人们就不会在不打算写入时意外地产生副本。
So, the first style is generally preferable.
We do use a variation of the second style quite a bit in the codebase I'm currently working on though, because we want a big distinction between const and non-const usage.
In my specific example, we have getTessellation and getMutableTessellation. It's implemented with a copy-on-write pointer. For performance reasons we want the const version to be use wherever possible, so we make the name shorter, and we make it a different name so people don't accidentally cause a copy when they weren't going to write anyway.
虽然您的问题似乎只涉及一种方法,但我很乐意就风格提供意见。 就我个人而言,出于风格原因,我更喜欢前者。 大多数 IDE 都会为您弹出函数的类型签名。
While it appears your question only addresses one method, I'd be happy to give my input on style. Personally, for style reasons, I prefer the former. Most IDEs will pop up the type signature of functions for you.
我更喜欢第一个。 当本质上做同样事情的两件事看起来相同时,它在代码中看起来更好。 另外,您很少有一个非常量对象但想要调用 const 方法,因此这并不是什么大问题(在最坏的情况下,您只需要一个 const_cast<>)。
I would prefer the first. It looks better in code when two things that essentially do the same thing look the same. Also, it is rare for you to have a non-const object but want to call the const method, so that isn't much of a consern (and in the worst case, you'd only need a const_cast<>).
由于您隐藏了类的名称,因此这种关于样式的思考内容可能适用也可能不适用:
告诉这两个对象 MethodA 和 MethodB“get”或“getAsConst”有意义吗? 您会将“get”或“getAsConst”作为消息发送到任一对象吗?
在我看来,作为消息的发送者/方法的调用者,你是获得该值的人; 因此,为了响应此“获取”消息,您将向 MethodA / MethodB 发送一些消息,其结果就是您需要获取的值。
示例:如果 MethodA 的调用者是 SOA 中的一个服务,并且 MethodA 是一个存储库,则在该服务的 get_A() 内,调用 MethodA.find_A_by_criteria(...)。
Since you hide the names of the classes, this food for thought on style may or may not apply:
Does it make sense to tell these two objects, MethodA and MethodB, to "get" or "getAsConst"? Would you send "get" or "getAsConst" as messages to either object?
The way I see it, as the sender of the message / invoker of the method, you are the one getting the value; so in response to this "get" message, you are sending some message to MethodA / MethodB, the result of which is the value you need to get.
Example: If the caller of MethodA is, say, a service in SOA, and MethodA is a repository, then inside the service's get_A(), call MethodA.find_A_by_criteria(...).
我看到的 MethodB 的主要技术缺点是,当对其应用泛型代码时,我们必须加倍代码才能处理 const 和非 const 版本。 例如:
假设 T 是一个可排序对象(即,我们可以使用运算符 < 与 T 类型的对象进行比较),假设我们想要找到两个 MethodA(分别是两个 MethodB)之间的最大值。
对于 MethodA,我们需要编写的代码是:
该代码适用于 T 类型的 const 对象和非 const 对象:
当我们想要将这段简单的代码应用于遵循 MethodB 约定的内容时,问题就出现了:
为了使 MethodB 能够工作在 const 和非 const 版本上,我们都必须使用已经定义的 getMax,但要添加以下版本的 getMax:
结论,通过不信任编译器对 const 的使用,我们会因为创建两个泛型而给自己带来负担当一个应该足够的时候就可以发挥作用。
当然,如果有足够的偏执,第二个模板函数应该被称为 getMaxAsConst...因此,问题将通过所有代码传播自身...
:-p
The major technological drawback of MethodB I saw is that when applying generic code to it, we must double the code to handle both the const and the non-const version. For example:
Let's say T is an order-able object (ie, we can compare to objects of type T with operator <), and let's say we want to find the max between two MethodA (resp. two MethodB).
For MethodA, all we need to code is:
This code will work both with const objects and non-const objects of type T:
The problem comes when we want to apply this easy code to something following the MethodB convention:
For the MethodB to work on both const and non-const version, we must both use the already defined getMax, but add to it the following version of getMax:
Conclusion, by not trusting the compiler on const-ness use, we burden ourselves with the creation of two generic functions when one should have been enough.
Of course, with enough paranoia, the secondth template function should have been called getMaxAsConst... And thus, the problem would propagate itself through all the code...
:-p
第一个允许更改变量类型(无论是否为 const),而无需进一步修改代码。 当然,这意味着不会通知开发人员这可能已偏离预期路径。 因此,这实际上取决于您是否重视能够快速重构,或者拥有额外的安全网。
The first allows changes to the variable type (whether it is
const
or not) without further modification of the code. Of course, this means that there is no notification to the developer that this might have changed from the intended path. So it's really whether you value being able to quickly refactor, or having the extra safety net.第二个与匈牙利表示法有关,我个人不喜欢它,所以我会坚持使用第一种方法。
我不喜欢匈牙利表示法,因为它增加了我在编程中通常讨厌的冗余。 这只是我的意见。
The second one is something related to Hungarian notation which I personally DON'T like so I will stick with the first method.
I don't like Hungarian notation because it adds redundancy which I usually detest in programming. It is just my opinion.