探索 C++ 中的 const 关键字
感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️
摘要:
在某些情况下,C++ 中的const关键字根本无法保护我们设定的常量量不受到修改const限定符并不总是按照我们期望的方式工作。在本文中,我们将看到const无法保护我们免受修改的一些情况。const关键字在几乎所有 C++ 程序中都有得到广泛使用,它象征着常量变量、对象、函数等的概念,旨在禁止我们在一定范围内操纵和更改内存位置的内容。然而,正如夏洛克·福尔摩斯所说的:“没有什么比显而易见的事实更具欺骗性了。”
关键词
: C++,const
声明:
本文作者原创,转载请附上文章出处与本文链接。
文章目录
- 摘要:
- Ⅰ.1 const 规则
- Ⅱ.1 类 const 成员函数
Ⅰ.1 const 规则
在本文中,我不会深入探讨这些const
规则,而只是简要介绍一下const
和我认为对我想讨论的观点至关重要的想法。
我们先从const
的基本规则开始,最基本的const
例子是常量变量:
const int a = 42;
在此示例中,我们初始化一个常量整数,其值为42
。任何const
变量都应在创建阶段初始化(因为以后无法初始化)。变量初始化后,就无法更改它。
常量位置:const
关键字可以写在以下类型的多个位置:
const int a = 5;
int const b = 6;
结果是相同的,在两种情况下,变量都是常量。然而,当指针加入其中时,const
和*
相对位置不同时,修饰的s常量则会不同。
int val;
const int* a = &val;
在上面的这个例子中,我们先初始化了一个名为val
可变int
变量,以及一个const
指向它的指针a
。现在因为a
它只是一个部分const
指针,所以这里实际上只适用于指针的值,而不是指针本身,这意味着我们可以修改这个指针以指向另一个变量,但我们不能通过这个指针修改变量内容。例如:
int val;
const int* a = &val;
// *a = 5; // 不能编译。int内容由const限定符保护。
int val2;
a = &val2; // 能通过编译
这也意味着我们可以创建指针变量而不在创建阶段为其分配值:
// const val; // doesn't compile
const int* a; // Works.
如果我们想保护指针,我们必须更改const
限定符的位置。让我们尝试const
在此示例中限定符的不同可能位置:
const int* a; // int内容受到保护
int const* b; // int内容受到保护
int val;
int* const c = &val; // 指针被保护,
// 因此必须在创建阶段初始化.
我们可以组合不同的const
位置,只要它们在同一个变量中不重复含义:
int val;
const int* const a = &val; // 指针及其内容都受到保护.
int const* const b = &val; // 指针及其内容都受到保护.
// const int const c; // 不能编译,因为const重复了
// 两个const限定符具有相同的含义.
规则很简单,如果const
是类型中的第一个限定符,则const
将应用于该类型的下一个元素。否则,它总是应用于它的前一个分量。
附注:常量指针等效于引用变量,例如:
int val;
int &a = val;
int *const b = &val;
这里的变量a
和b
含义是一样的,都是保护指针指向不被改变。
Ⅱ.1 类 const 成员函数
现在我们知道了常量变量的规则,让我们来讨论一下常量函数,常量函数被定义为不能修改类变量的函数。例如:
class A {
public:
void func() const {
// a = 5; // 不能编译
}
private:
int a;
};
一切看起来正常,让我们检查另一个案例:
class A {
public:
void func() const {
// a = &val; // 不能编译
}
private:
int *a;
int val;
};
到目前为止,一切似乎都很好。如果函数是const
,则无法修改类的成员。是时候稍微打破一下这条规则了:
class A {
public:
A() : a(&val) {}
void func() const {
*a = 42; // 能编译,Wait, WHAT?!
}
private:
int *a;
int val;
};
在这个例子中,我们通过常量成员函数中的指针成员修改了成员变量的内容。
将此函数标记为const
函数是一个错误,如果有人中继此const
限定符,则可能会导致错误。此函数实际上执行了隐藏操作const_cast
,但不应该这样做。为了解决这个问题,正确的做法是从此函数中删除const
限定符。
代码检查工具有时会建议我们为该函数添加限定符const
,因为编译器允许这样做,但我们不应该这样做。const
在为类的函数添加限定符之前,应始终仔细考虑该函数是否会修改类的状态/变量。
让我们看一个更加令人困惑的例子:
class A {
public:
A() : a(val) {}
void func() const {
a = 42; // Oh no...
}
private:
int &a;
int val;
};
这次,我们在修改内容时甚至不需要*
。而按照语言标准,这是完全合法的。
end~