当我在学校时,教授们把它敲进了我的脑海,同事们在代码审查中跳了起来,而且几乎所有的C ++教科书都出现了:" accessor" (又名"选择器"或"getter")方法必须标记为const
。如果它没有更改或改变数据,请将其标记为const
。
为什么呢?如何调用访问者来修改私有数据?
在下面的示例中,我设置了一个简单的类和一个访问器。如何getBrand()
用于修改私人数据?在我看来,它不能;那么为什么我们需要标记它const
?
换句话说,我是否正确地说getBrand()
在实践中不可能改变私有财产?
示例:
#include <iostream>
#include <string>
class Cheese {
public:
Cheese(std::string brand):brand_(brand) {}
std::string getBrand() { return brand_; } // Intentionally not marked const
private:
std::string brand_;
};
int main() {
Cheese cheddar("Cabot clothbound");
std::cout << "Brand: " << cheddar.getBrand() << std::endl;
return 0;
}
答案 0 :(得分:10)
实际上非常简单:如果方法不是const,则无法在const
个对象上使用它 - 但您确实希望能够使用它。在课堂上,你无法实现
void print_brand(const Cheese& cheese);
(除非你是const-cast,你不应该这样做。)
另外,如果你确实将它设为const,而不是返回你的字符串的副本 - 可能会或可能不会被优化掉,你可以实现:
const std::string& getBrand() const { return brand_; }
返回引用,或者
std::string_view getBrand() const { return brand_; }
不会将您的API“提交”到字符串类(请参阅string_view
here;它只是正式添加到C ++ 17中的语言中,但可以{{1最近的编译器。)
答案 1 :(得分:3)
漏洞在哪里?
答案是函数名称可以存在,但包含对const的引用的接口不能。
示例:
#include <iostream>
#include <string>
// this function name lies
void i_wont_touch_your_cheese(std::string& s)
{
// uh-oh - I lied!
s = "lol, I touched your cheese!";
}
// this one cannot. The compiler won't allow it
void i_really_wont_touch_your_cheese(const std::string& s)
{
// compiler error here!
// cheese is safe
s = "lol, I touched your cheese!";
}
int main() {
auto cheese = std::string("untouched cheese");
i_wont_touch_your_cheese(cheese);
std::cout << cheese << std::endl;
cheese = "more untouched cheese";
i_really_wont_touch_your_cheese(cheese);
std::cout << cheese << std::endl;
return 0;
}
答案 2 :(得分:2)
严格地说你所写的方法并不会改变班级成员。如果您将其标记为const
,则编译器会完全阻止它改变成员。但是,让我们在这里深入挖掘一下。
通常,您只需编写一次代码,但多次阅读/查看。标记方法const
允许未来的读者查看它,并且立即知道该方法无法更改类状态,因为编译器会捕获它。例如,如果您不小心写了size_t empty() const { return size_ = 0; }
(其中size_
是成员变量),编译器将捕获您的拼写错误。如果你没有标记方法const,你会有一个微妙的错误。
但更重要的是,const
方法只能调用其他const
方法。考虑一下,如果你有一个方法将类状态作为输入,做一堆工作并返回一个结果。如果用于执行其工作的getter
方法是非常量的,那么长而复杂的方法也必须是非常量的,这使得代码理解很多更难。
答案 3 :(得分:1)
关键字const
的功能保证使用她,不要更改给定的对象。因此,如果您希望将对象打印到某个函数或特别是对于operator<<
外部类,则应该仅使用带有关键字const
的方法。
std::ostream &operator<<(std::ostream& str, const Object& obj)
{
return str << obj.someFunctionConst() << std::endl;
}
有错误的函数(编译错误)
std::ostream &operator<<(std::ostream& str, const Object& obj)
{
return str << obj.someFunctionWithoutConst() << std::endl;
}
答案 4 :(得分:0)
const
不是关于漏洞!从理论上讲,它不会强制执行安全性,安全性或其他任何操作。没有什么能阻止你应用const-cast来删除它或使用关键字mutable
来改变某些东西。
const
有助于使您的代码更清晰。请参阅Const-Correctness文章并详细解释该概念。
const
查看某些内容时,您会合理地预期它不会改变状态。声明int Class:foo() const;
告诉我foo()
不会改变对象的状态,可以从任何地方调用它。const
具有传染性。您使用的越多,您使用它的次数就越多。 bool Class::bar();
如果需要致电const
,则必须为foo()
。const &
传递给函数void zoo(const Class &cls);
,那么您知道zoo()
将无法修改cls
的状态。