C++核心准则Con.2:默认情况下,将成员函数定义为const类型
共 3959字,需浏览 8分钟
·
2020-08-17 17:23
秋英
Con.2: By default, make member functions const
Con.2:默认情况下,将成员函数定义为const类型
Reason(原因)
A member function should be marked const unless it changes the object's observable state. This gives a more precise statement of design intent, better readability, more errors caught by the compiler, and sometimes more optimization opportunities.
只要没有修改对象的可观察状态,就应该将成员函数定义为const类型。这是设计意图的更清晰表达,可以带来更好的可读性,方便编译器捕捉更多的错误,而且有时还会带来更多的优化机会。
Example, bad(反面示例)
class Point {
int x, y;
public:
int getx() { return x; } // BAD, should be const as it doesn't modify the object's state
// ...
};
void f(const Point& pt)
{
int x = pt.getx(); // ERROR, doesn't compile because getx was not marked const
}
Note(注意)
It is not inherently bad to pass a pointer or reference to non-const, but that should be done only when the called function is supposed to modify the object. A reader of code must assume that a function that takes a "plain" T* or T& will modify the object referred to. If it doesn't now, it might do so later without forcing recompilation.
传递指针或者引用给非常量也不是说一定不好,但是它只应该发生在调用一个假定会修改对象值的情况下。代码的读者必须假设接受原始T*或T&参数的函数会修改(指针或引用,译者注)参照的对象。如果(修改,译者注)没有发生在现在,那么可能是以后会发生而且不需要重新编译。
Note(注意)
There are code/libraries that offer functions that declare a T* even though those function do not modify that T. This is a problem for people modernizing code. You can
有些代码/库提供的函数定义了T*参数却没有修改T。这对于更新代码使其适用现在C/C++的人来说是一个问题,你可以
update the library to be const-correct; preferred long-term solution
将库更新到正确定义const属性的版本;优先使用长期的解决方案。
"cast away const"; best avoided
使用常数类型转换;最好避免这种做法。
provide a wrapper function
提供一个包装函数
Example(示例):
void f(int* p); // old code: f() does not modify `*p`
void f(const int* p) { f(const_cast(p)); } // wrapper
Note that this wrapper solution is a patch that should be used only when the declaration of f() cannot be modified, e.g. because it is in a library that you cannot modify.
注意包装方式是一种只能在f()的声明无法改变的情况下使用的“补丁”方案。例如当函数使库的一部分而无法修改时。
Note(注意)
A const member function can modify the value of an object that is mutable or accessed through a pointer member. A common use is to maintain a cache rather than repeatedly do a complicated computation. For example, here is a Date that caches (memoizes) its string representation to simplify repeated uses:
const类型的成员函数可以通过mutable对象或者借助指针成员修改对象的值。一个通常的用法是维护一个缓存以回避重复的计算。例如,下面的代码中的Data类就为简单的重复使用缓存(记忆)了一个字符串表现。
class Date {
public:
// ...
const string& string_ref() const
{
if (string_val == "") compute_string_rep();
return string_val;
}
// ...
private:
void compute_string_rep() const; // compute string representation and place it in string_val
mutable string string_val;
// ...
};
Another way of saying this is that constness is not transitive. It is possible for a const member function to change the value of mutable members and the value of objects accessed through non-const pointers. It is the job of the class to ensure such mutation is done only when it makes sense according to the semantics (invariants) it offers to its users.
说明这件事的另一个方式是常量属性是不可传递的。一个const成员函数修改mutable成员的值,或者通过一个非const指针访问对象值都是可能的。保证这种修改只有在符合其向用户提供的语义(不变量)是这个类的工作。
See also: Pimpl
Enforcement(实施建议)
Flag a member function that is not marked const, but that does not perform a non-const operation on any member variable.
如果一个函数没有定义为const类型,有没有执行针对任何成员变量的非常量操作,标记它。
原文链接
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#con2-by-default-make-member-functions-const
新书介绍
《实战Python设计模式》一书是作者最近出版的新书,拜托多多关注!
本书利用Python 的标准GUI 工具包tkinter,通过可执行的示例对23 个设计模式逐个进行说明。这样一方面可以使读者了解真实的软件开发工作中每个设计模式的运用场景和想要解决的问题;另一方面通过对这些问题的解决过程进行说明,让读者明白在编写代码时如何判断使用设计模式的利弊,并合理运用设计模式。
对设计模式感兴趣而且希望随学随用的读者通过本书可以快速跨越从理解到运用的门槛;希望学习Python GUI 编程的读者可以将本书中的示例作为设计和开发的参考;使用Python 语言进行图像分析、数据处理工作的读者可以直接以本书中的示例为基础,迅速构建自己的系统架构。
觉得本文有帮助?请分享给更多人。
关注微信公众号【面向对象思考】轻松学习每一天!
面向对象开发,面向对象思考!