为什么我们需要const方法?

时间:2019-12-04 03:48:20

标签: c++

类函数const用于告诉编译器类函数不会更改成员变量。因此,该类型的常量对象可以安全地调用它。下面是一个简单的示例。

#include <iostream>
using namespace std;

class X {
private:
  int a{1};

public:
  void PrintA() const {
    cout << a << "\n";
  }
};

int main() {
  const X x;
  x.PrintA();
}

我们告诉编译器#PrintA是const,因此常量对象可以安全地调用它。但是,似乎编译器实际上很聪明,可以独立于const关键字检测函数是否为只读。如果我在上面的代码中像这样添加a=10

#include <iostream>
using namespace std;

class X {
private:
  int a{1};

public:
  void PrintA() const {
    cout << a << "\n";
    a = 10;
  }
};

int main() {
  const X x;
  x.PrintA();
}

我知道

exp.cpp: In member function ‘void X::PrintA() const’:
exp.cpp:11:9: error: assignment of member ‘X::a’ in read-only object
     a = 10;

换句话说,const关键字不能欺骗编译器以允许常量对象的变异。所以我的问题是,为什么开发人员需要声明方法const?看起来,即使没有该提示,编译器也可以区分只读方法和非只读方法,因此可以正确捕获尝试使常量对象发生突变的情况。

2 个答案:

答案 0 :(得分:4)

这不是提示-它是方法接口的一部分。如果删除const,PrintA中的错误将消失,而main中将出现错误。出于需要public和private的相同原因,您需要const来定义所需的接口。然后,编译器将检查以确保您不违反声明的接口。

答案 1 :(得分:2)

  

编译器区分只读方法和非只读方法

首先考虑编译器使用今天存在的const来完成此操作的难易程度。

  • 要确定PrintA的实现是否遵守规则,编译器只需要查看该实现即可。
  • 要确定x.PrintA();是否对const X x;有效,只需要声明PrintA

现在想象一下,如果我们没有功能级别的const

  • 要确定PrintA的实现是否遵守规则,编译器必须确定它是否不是只读的,然后扫描整个程序以查找是否曾经在{{1}上被调用}对象。

我敢肯定,这会使大型程序的链接时间大大膨胀。

但是const函数是一个值得关注的问题。想象一下,一个派生类使用只读实现覆盖,但是另一种派生类使用非只读实现覆盖。然后,如果在virtual对象上调用了这种方法,那么编译器将要做什么,因为它可能无法在编译时确定将调用哪种实现?我们是否只需要排除虚函数就不可能调用const对象?不幸的是,这是有限的。

此外,当调用者与实现跨越DLL边界(即使对于非虚拟函数)分开时,这种想法也行不通,因为它们仅在运行时连接在一起。

因此,总的来说,如果我们要让编译器不得不弄清楚方法是否以const方式实现,那么要声明const对象就显得更加困难/困难。