为什么我们需要常量方法?
Why Do We Need const methods?
class 函数 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 关键字无关。如果我像这样在上面的代码中添加一个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,PrintA 中的错误将消失,您将在 main 中收到错误。你需要 const 的原因与你需要 public 和 private 的原因相同 -- 来定义你想要的接口。然后,编译器将进行检查,以确保您没有违反已声明的接口。
区分只读和非只读方法
首先考虑编译器使用当前存在的const
指定可以多么容易地执行此操作。
- 要确定
PrintA
的实现是否遵守规则,编译器只需查看该实现。 - 要确定
x.PrintA();
是否对const X x;
有效,它只需要声明PrintA
。
现在想象一下,如果我们没有功能级const
- 若要确定
PrintA
的实现是否遵守规则,编译器必须确定它是否不是只读的,然后扫描整个程序以查找它是否曾经在const
对象上调用过。
我敢肯定,这会大大增加大型程序的链接时间。
但是,一个重要的问题是virtual
功能。假设一个派生类使用只读实现重写,但随后另一个派生类使用非只读实现重写。那么,如果在const
对象上调用这样的方法,编译器该怎么办,因为它可能无法在编译时确定将调用哪个实现?我们是否只需要排除虚拟可以调用常量对象?不幸的是,这将是有限的。
此外,当调用方与实现跨 DLL 边界分离时(即使对于非虚拟函数(,这个想法也行不通,因为它们仅在运行时连接在一起。
因此,总的来说,如果我们将其留给编译器来确定方法是否以常量方式实现,那么能够声明 const 对象对我们来说似乎更加困难/问题。
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 是否有内置方法可以强制转换为不同的基础类型,但保留常量限定符?
- 为什么常量方法可以采用非常量引用?
- 常量方法中的非常量 lambda 捕获
- 友元方法作为常量
- 一个模板方法,用于同时接受常量和非常量参数
- 使用大量已知常量变量的正确方法
- 使用迭代器替换映射中的常量项的方法
- 一种优雅或至少可行的方法,用于使用和接受具有重载方法和运算符的不同大小的文字数组常量
- 初始化不是整数的巨大常量多维数组的最佳方法是什么?
- Gmock 常量方法不调用,而是调用原始方法
- 为什么我们需要常量方法?
- 从模块导出全局常量的正确方法是什么?
- 模板常量/非常量方法
- 定义常量变量的最佳方法
- 常量字符*的模板方法专用化
- 常量静态成员函数:有另一种方法可用吗?
- 使方法常量后声明不兼容
- c++ 是否提供了一种使整个结构常量(不可修改)的方法?
- 当底层OpenGL状态被修改时,我应该声明一个方法常量吗