T& f() { // some code ... }
const T& f() const { // some code ... }
Run Code Online (Sandbox Code Playgroud)
我现在已经看过几次了(在我迄今为止研究的介绍性书中).我知道第一个const使返回值为const,换句话说:不可修改.我相信第二个const允许为const声明的变量调用该函数.
但是为什么你会在同一个类定义中同时拥有这两个函数?编译器如何区分这些?我相信第二个f()(带const)也可以调用非const变量.
Mik*_*our 26
但是为什么你会在同一个类定义中同时拥有这两个函数?
两者都允许您:
const
对象上调用函数,只查看结果.只有第一个,你无法在一个const
对象上调用它.只有第二个,你不能用它来修改它返回引用的对象.
编译器如何区分这些?
它const
在const
对象上调用函数时(或通过引用或指针const
)选择重载.否则它会选择另一个过载.
我相信第二个f()(带const)也可以调用非const变量.
如果这是唯一的超载,那么它可以.对于两个重载,const
将选择非过载.
rav*_*avi 13
但是为什么你会在同一个类定义中同时拥有这两个函数?
有时您希望为相同的操作提供不同的语义,具体取决于它是否在const
对象OR non-const
对象上调用.我们举一个例子std::string
: -
char& operator[](int index);
const char& operator[](int index) const;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,当operator[]
通过const
对象调用时,您不会让用户更改字符串的内容.
const std::string str("Hello");
str[1] = 'A'; // You don't want this for const.
Run Code Online (Sandbox Code Playgroud)
另一方面,如果是非const字符串,则允许用户更改字符串的内容.这就是为什么不同的超载.
编译器如何区分这些?
编译器检查是否在const
对象OR non-const
对象上调用该方法,然后适当地调用该方法.
const std::string str("Hello");
cout << str[1]; // Invokes `const` version.
std::string str("Hello");
cout << str[1]; // Invokes non-const version.
Run Code Online (Sandbox Code Playgroud)
没有const的第一个允许调用者修改对象,该对象通常是调用其方法的类的成员.
第二个,我们的宿主类处于只读模式,也允许对其成员进行只读访问.
默认情况下,如果在constness规则下允许,则调用非const版本.
其中一个最常见的例子是某种集合/数组类型类.
class Array
{
private:
MyType members[MySize];
public:
MyType & operator[]( size_t index );
const MyType & operator[]( size_t index ) const;
};
Run Code Online (Sandbox Code Playgroud)
假设它们已经实现,它可能是模板,或者它们是具体的类型和大小.我正在演示const过载.
现在我们可以让某人使用该课程.您可能想要设置一个值.
Array myArray;
myArray[ 3 ] = myObject;
Run Code Online (Sandbox Code Playgroud)
或者你可能只是阅读它:
const Array& myArrayRef = getArrayRef(); // gets it to read
const MyType & myValueRef = myArrayRef[ 3 ];
Run Code Online (Sandbox Code Playgroud)
因此,您可以看到我可以使用表示法来设置值并读取一个值.与此同时operator[]
,您可以将此技术应用于任何方法.
Qt 框架中有一个非常好的例子。
看一下QImage类。
有两个公共函数:
const uchar* scanLine (int i) const;
uchar* scanLine (int i);
Run Code Online (Sandbox Code Playgroud)
第一个仅供读取访问。第二种是针对需要修改扫描线的情况。
为什么这种区别很重要?因为Qt使用隐式数据共享。这意味着,如果您执行以下操作,QImage 不会立即执行深层复制:
QImage i1, i2;
i1.load("image.bmp");
i2 = i1; // i1 and i2 share data
Run Code Online (Sandbox Code Playgroud)
相反,仅当您调用实际修改两个图像之一的函数(例如非常量 scanLine)时,才会复制数据。