const即constant的缩写,意为持久不变的.
1.通过const修饰来定义常量
在常量定义前加const,可以使定义的常量只读,不能修改.如:
int main(){
const int a = 12;
a = 13;//编译报错:表达式必须是可修改的左值
cout<
2.const修饰指针
const修饰指针有三种情况.
(1)const修饰指针
当以下面形式声明指针时,则为const修饰指针,声明的指针p为常量指针.
int main() {
int a = 12;
const int* p = &a;//p为常量指针
return 0;
}
常量指针:指针指向的是常量.即指针的指向可以修改,但指针指向的值不能修改.
int main() {
int a = 12;
int b = 10;
const int* p = &a;//p为常量指针
*p = b;//错误,试图修改指向的值.编译报错:表达式必须为可修改的左值
p = &b;//正确,修改指针的指向,可以通过编译
return 0;
}
(2)const修饰常量
当以下面形式声明指针时,则为const修饰常量,声明的指针p为指针常量.
int main() {
int a = 12;
int* const p = &a;//p为指针常量
return 0;
}
指针常量:指针本身为常量.即指针指向的值可以修改,但指针的指向不能修改.
int main() {
int a = 12;
int b = 10;
int* const p = &a;//p为指针常量
*p = b;//正确,修改指针指向的值,可以通过编译
p = &b;//错误,试图修改指针的指向,报错:表达式必须为可修改的左值
return 0;
}
(3)const既修饰指针,又修饰常量
当以下面形式声明指针时,则为const既修饰指针,又修饰常量.
int main() {
int a = 12;
const int* const p = &a;
return 0;
}
指向的值和指针的指向都不能改变.
int main() {
int a = 12;
int b = 10;
const int* const p = &a;//p为指针常量
*p = b;//编译不通过
p = &b;//编译不通过
return 0;
}
(3)const修饰指针总结
3.const修饰引用
const修饰引用的情况只有一种,即:
int main() {
int a = 12;
const int& r = a;
int& const r = a;//这样写跟不加const没区别
r = 10;//编译不通过,r为常量不能修改
return 0;
}
当用const修饰引用时,可以直接赋右值给引用.
int main() {
int& r = 10;//编译不通过,必须赋左值
const int& const_r = 10;//编译通过
//使用常量(字面量)对const引用进行初始化时,C++编译器会为常量值分配空间,并将引用名作为这段空间的别名
//int temp = 10;
//const int &ci = temp;
return 0;
}
4.使用场景
(1)定义全局常量
类似于define宏定义,将不会变的常量进行定义,方便调用.如:
const double PI = 3.14159625;
int main(){
return 0;
}
(2)修饰形参
当我们需要传递一个较大的对象给函数作为参数时,为了节省内存,可以将函数参数定义为指针或者引用类型,然后将对象的指针或引用传递给参数即可.为了防止函数中对形参进行修改(因为这样会影响到实参),一般将形参加上const修饰符,从而使其变为只读.如:
struct User {
int uid;
string pwd;
};
void user_print(const User& user) {
user.uid = 300;//编译不通过
cout << "uid: " << user.uid << endl;
cout << "pwd: " << user.pwd << endl;
}
int main() {
User user = { 316,"123456" };
user_print(user);
return 0;
}
5.面向对象中的const
(1)const修饰成员函数
- const修饰的成员函数称为常函数
- 常函数内不可以修改成员属性
- 成员属性声明时加关键字mutable后,在常函数中依然可以修改
class A {
private:
int a;
mutable int b;
public:
void show_A() const{
a = 10;//无法通过编译
b = 20;
}
};
本质:每个成员函数都有一个隐藏的参数,即this指针,this指针的本质就是一个指向自身对象的一个指针常量(Type* const this),所以this指针的指向不会变,永远指向自己.给成员函数加const修饰相当于给this指针又加上了const修饰指向的值,即(const Type* const this),这样,this指针的指向不会变,指向的值也不允许改变.
(2)const修饰对象
- 声明对象前加const称该对象为常对象
- 常对象只能调用常函数,普通对象既可以调用普通成员函数,也可以调用常函数
- 常对象不能修改属性
class A {
private:
int a;
mutable int b;
public:
void show_A() const{
}
void show() {
}
};
int main() {
const A a;
a.show_A();//正确
a.show();//错误
return 0;
}
6.const与define宏定义的区别
- 作用阶段:define只在预处理阶段起作用,而const在编译和运行阶段起作用.因此,const可以进行调试而define不行;
- 作用方式:define为简单的字符串替换,const有类型检查,因此const比define更安全,不易出错;
- 存储方式:define只是进行展开,有多少地方使用,就替换多少次,它定义的宏常量在内存中有若干个备份;const定义的只读变量在程序运行过程中只有一份备份。所以const比define要节省内存.
结论:⚡const⚡与⚡define⚡相⚡比⚡,那⚡我⚡还⚡是⚡感⚡觉⚡我⚡们⚡const⚡牛⚡逼⚡
7.const_cast
const_cast用于去除const限定,但其目的并不是修改const修饰的变量(而且也修改不了)
使用场景举例:
我们可能调用了一个参数不是const的函数,而我们要传进去的实际参数确实const的,但是我们知道这个函数是不会对参数做修改的。于是我们就需要使用const_cast去除const限定,以便函数能够接受这个实际参数。如:
void fun(int* a) {
//*a++;
cout << *a;
}
void main(){
const int constant = 12;
int* p = const_cast (&constant);//通过const_cast去除const限定
fun(p);
}
传统转换方式实现const_cast
const int constant = 12;
int* p = (int*)&constant;//直接通过显示转换,强转指针类型
详见:https://www.cnblogs.com/ider/archive/2011/07/22/cpp_cast_operator_part2.html
参考文章:https://blog.csdn.net/weixin_38279101/article/details/112355990
https://blog.csdn.net/weibo1230123/article/details/81981384