修饰符const
const 关键字 让被修饰的对象为只读,不可以修改其值。
应用场景
const的应用场景主要有三种,第一种是修饰普通变量,第二种是修饰指针或引用,第三种是修饰成员函数。
常变量
可以读取变量,不可进行写入操作。
//可以直接用常量初始化
const int a = 6;
a = 9; //错误, a 是可读类型
//可以用变量初始化
int b = 3;
const int c = b;
像这种情况,const 修饰的变量只能定义时初始化进行赋值,且必须初始化。
const int d; //错误,未进行初始化
const int d = 5; //正确,进行了初始化
指针和引用
先来介绍两个概念:
- 顶层const: 不可修改对象的值
- 底层const: 不可修改指向对象的值
int a = 5;
int b = 6;
const int *p = &a; //这个是底层const,无法修改指向对象的值
*p = 15; //错误,无法修改指向对象的值
a = 15; /* 这是正确的,const 只是无法通过 p 对象 来修改指向 a 对象的值,
但通过 a 对象本身可以进行修改 */
p = &b; //这个是允许的,可以修改 p 所指向的对象
int *const q = &a; //顶层const,无法修改对象的值
q = &b; //不可以修改 q 对象的值
*q = 20; //这个是可以的,其指向的对象没有限制
对于引用来说,它本身不是对象,只是对象的别名,像标签一样,与其指向的对象绑定在一起,但 const 修饰之后 又有一些特例:
/* 可以绑定非常量对象 */
int d = 2;
const int &p = d;
/* 可以绑定常量 */
int &a = 0; //错误
const &a = 0; //正确
/* 可以绑定常量表达式 */
int b = 1;
int &c = 2*b; //错误
const int &c = 2*b; //正确
/* 其实对于对于常量引用来说,只要等号右边可以转化为引用所指定的类型,都可以进行初始化 */
成员函数
对成员函数用 const 修饰,意味着在这个函数内对 类的任何成员不能进行修改。
#include <iostream>
class Entity {
private:
int a;
int b;
public:
int get() const {
//a++; // 这是错误的,const 修饰意味着不能对类成员进行修改
return a;
}
};
void put(const Entity &x) {
std::cout << x.get() << std::endl;
}
int main() {
Entity e;
put(e);
}
上面的程序显然是对的,那么对其进行小的修改:
#include <iostream>
class Entity {
private:
int a;
int b;
public:
int get(){ //删除了const
return a;
}
};
void put(const Entity &x) {
std::cout << x.get() << std::endl; /*报错,因为参数类型 const 修饰
而get()汉书可能修改 x,尽管它并未实现,
但它存在实现的可能*/
}
int main() {
Entity e;
put(e);
}
稍微总结一下就是,const 修饰的成员函数,保证了该函数无法对类的任何成员进行修改。这种修饰是绝对严格的,即使你并未对其进行修改,但存在可能性,就会报错,举一个例子:
#include <iostream>
void putnum(int &x) { /*将其改变为putnum(const int &x) 或 putnum(int x) 或
putnum(const x) 便正确了,排除修改成员变量的可能*/
};
class Entity {
private:
int a = 1;
int b = 2;
public:
int get() const{
putnum(a); /*这里报错了,因为putnum()函数存在修改成员变量a的可能,
即使什么都没做*/
return a;
}
};
void put(Entity& x) {
std::cout << x.get() << std::endl;
}
int main() {
Entity e;
put(e);
}
默认状态下,const对象仅在文件内有效
这是一个补充知识点:如果有多个文件的话,const 修饰的变量只能在被定义的编译单元中使用,没有可共享性,也就是内部链接。想要实现const 对象在不同编译单元间的共享,需要在定义和声明前都加上 extern 关键字,注意,是定义和声明都需要 extern 关键字。
/* 在main.cpp中 */
const int e = 7; //错误,这种定义是不正确的
extern const int e = 7; //正确
/* 在fuc.cpp中*/
extern const int e;
constexpr 和 常量表达式
常量表达式:指的是值不变且在编译时就知道结果。
const int a = 1; //是常量表达式
const int b = a + 1; //是常量表达式
int c = 3; //不是常量表达式,可修改其值
const int d = get(); //不是常量表达式,在运行时才知道结果
constexpr 变量
变量,可用constexpr修饰来让编译器检测变量值是否为常量表达式,声明为constexpr的变量一定是一个常量,且用常量表达式初始化。
constexpr int a = 1;
constexpr int b = a + 1;
constexpr int c = fuc(); //只有当fuc()是constexpr函数时,才是正确声明
constexpr指针
constexpr指针只是对指针本身进行限制,对指向对象不起作用。
int a =5;
constexpr int *p = &a; //指针是常量,不可修改
const int *q = &a; //指针指向对象是常量,不可修改
标签:const,常量,修改,int,constexpr,对象
From: https://www.cnblogs.com/import-this05/p/18164768