文章目录
const 定义普通变量
# define PI 3.1415926
const double Pi = 3.1415926;
效果上看,使用 #define
和 const
定义的普通常量效果一致。但是内部实现上,还是有区别
const
会进行类型检查而#define
不会,因此const
更安全const
定义的变量只有在被引用时才被分配内存,而且只分配一次,之后传递的都是指针。而#define
作为宏定义每次用到都会立即分配相应内存,因此const
更节省空间,避免了重复分配相同内容的内存空间- 编译器通常不为普通
const
常量分配存储空间,而是保存在符号表中,这使得它成为一个编译期间的常量,没有了读写内存的操作,效率极高。
结论: 能用 const 就多用 const
const 定义指针变量
总结起来就是, const 左边的忽略, 除*
外的变量类型忽略,从 const 往右看,右边的整体是常量,但越过去就是变量还是变量
// pContent本身是const常量指针,就指向一个固定的内存地址,但是所指向的该内存里的内容是可以修改的,
// 即 pContent 不可修改, 但是 *pContent 可以修改.
char * const pContent; // => (char*) const pContent;
// pContent本身是一个普通指针,但指向的内容是一个(const char) 的不可变常量
// 也就是说 pContent 可变,但是 *pContent 不可变.
// pContent = &whatever; //this is OK
// *pContent = *pAnotherContent; // error, expression must be a modifiable lval.
const char * pContent; // => (const char) *pContent;
char const * pContent;
// 都不可变
const char* const pContent;
举个例子, 在 链表 操作中, 如果我们定义一个操作 AddToTail, 那么
void AddToTail(LinkedList * pHead, ElemType val) {
phead = nullptr; // OK!
*phead = nullptr; // OK!
}
void AddToTail(LinkedList * const pHead, ElemType val) {
phead = nullptr; // // error, expression must be a modifiable lval!
*phead = nullptr; // OK!
}
void AddToTail(const LinkedList * pHead, ElemType val) {
phead = nullptr; // OK!
*phead = nullptr; // error, expression must be a modifiable lval!
}
void AddToTail(LinkedList const * pHead, ElemType val) {
phead = nullptr; // OK!
*phead = nullptr; // error, expression must be a modifiable lval!
}
void AddToTail(const LinkedList const * const pHead, ElemType val) {
phead = nullptr; // error, expression must be a modifiable lval!
*phead = nullptr; // error, expression must be a modifiable lval!
}
const 修饰函数
const 修饰函数参数
使用引用传参,增加效率同时防止修改
void foo(const TYPE& Var);
const 修饰函数返回值
一般不建议采用
// 无意义,因为参数返回本身就是赋值
const int foo();
// 对应的调用是 const int * p = foo2()
const int * foo2();
// 对应的调用是 int * const p = foo3()
int * const foo3();
const 类相关操作
const 修饰类成员变量
表示成员变量不能被修改,而且只能在初始化列表中赋值。
class A
{
const int i; // 定义常量成员函数
A(int value): i(value) {} // 只能在初始化列表中赋初值
};
const 修饰类成员函数
表明此函数不会修改类中的任何成员变量
class A
{
void foo() const;
};
外部使用时的 const 的类对象/指针/引用等等,都只能调用类的 const成员函数。防止对类中成员变量的修改。
class A
{
void foo(); // 普通成员函数
void bar() const; //const 成员函数
};
void fun(const A& a)
{
a.foo(); //error
a.bar(); // OK
}
const 类型转化为非const类型
使用 const_cast
进行转换
Best Practice
- 在搞懂
const
基本原理的前提下,放心大胆,多多益善地使用const
- 在函数参数中,应该更多地使用
const
引用或指针,const
一般的对象实例是没有意义的 - 任何不会修改成员变量的成员函数都应该声明为
const
类型
Ref
- 关于C++ const 的全面总结: 超级好文,全面的梳理总结
- C++中const和引用修饰变量和函数的总结: 代码示例多一些,
const 指针
与&引用
的区别说的非常好 - const成员变量与成员函数 : 简单的个人实践总结