【C/C++】const 详解

const 定义普通变量

# define PI 3.1415926
const double Pi = 3.1415926

效果上看,使用 #defineconst 定义的普通常量效果一致。但是内部实现上,还是有区别

  • 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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值