常量和不带相同的功能 - 何时以及为何?

Bek*_*eko 31 c++ const

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对象上调用它.只有第二个,你不能用它来修改它返回引用的对象.

编译器如何区分这些?

constconst对象上调用函数时(或通过引用或指针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)


Cas*_*Cow 5

没有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[],您可以将此技术应用于任何方法.


man*_*uel 5

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)时,才会复制数据。