常量折叠、类型强转#
#include <iostream>
int main()
{
//当你定义 const int MAX_AGE = 90; 时,编译器通常会进行常量折叠(Constant Folding)。这意味着在编译阶段,代码中所有出现 MAX_AGE 的地方都会被直接替换为数字 90;
//所以最下面的 std::cout << MAX_AGE << std::endl; 打印90
const int MAX_AGE = 90;
std::cout << MAX_AGE << std::endl;//90
int* a = new int;
*a = 2;
std::cout << *a << std::endl;//2
//如果不加 (int*)类型强转,提示 a value of type "const int *"cannot beassigned to an entity of type "int *"
//报错原因:1. 如果你能直接把 const int* 赋值给 int*,那么你就可以通过 *a = 100; 来修改 MAX_AGE 的值。这违背了 const 的初衷。为了保证代码的健壮性,编译器禁止这种**“权限扩大”**的行为(从“只读”变成“可读写”)。
// 2. 为什么加上(int*) 就不报错了?
// 当你加上(int*) 时,你正在使用强制类型转换(C - style Cast)。
// 这相当于你对编译器说:“我知道 MAX_AGE 是常数,我也知道我在把只读指针转成可读写指针,出了问题我负责,请闭嘴。” 编译器接收到了你的强制指令,于是停止报错。
a = (int*)&MAX_AGE;
std::cout << *a << std::endl;//90
*a = 5;
//如果MAX_AGE加了volatile关键字修饰,即 const volatile int MAX_AGE = 90;那
//么不会发生常量折叠,这里应该打印的是5
std::cout << MAX_AGE << std::endl;//90
//MAX_AGE 对应的内存空间,通过指针非法修改成了 5
std::cout << *a << std::endl;//5
std::cin.get();
}
const的修饰位置#
变量中#
#include <iostream>
int main()
{
const int MAX_AGE = 90;
//不能修改指针指向的地址里的值(但可以修改指针指向)
const int* a = new int;
//int const* a = new int;//跟上一句一个意思,const都是在*前面
//*a = 2;//报错
//由于a已经是const int*了,
//所以这里编译器没有像int* a时报错
a = &MAX_AGE;
std::cout << *a << std::endl;//90
//不能修改指针指向的地址里的值(但可以修改指针指向)
int* const b = new int;
*b = 2; //可修改地址里的值
//不可重新分配b指向其他地址
//b = &MAX_AGE;//报错
const int* const c = new int;
int const* const d = new int;
/*以下均编译不通过*/
//*c = 2;
//c = &MAX_AGE;
//*d = 2;
//d = &MAX_AGE;
/*以上均编译不通过*/
std::cin.get();
}
class中#
#include <iostream>
class Entity
{
private:
int m_X, m_Y;
static int s_X;
int* m_XP;
public:
//const: 在该方法中不允许修改成员变量
//禁止修改成员变量: 在该函数内部,你不能对任何非 static 成员变量进行赋值操作。
//禁止调用非 const 函数
int GetX() const
{
//m_X = 3;
s_X = 5;
//test();//会报错
return m_X;
}
//返回一个int指针,且该指针不能改变所存地址
//指向的值,也不能指向其他地址
const int* const GetXP() const
{
return m_XP;
}
void test() //const
{
}
};
int main()
{
std::cin.get();
}
形参中#
#include <iostream>
class Entity
{
private:
int m_X, m_Y;
int m_X1;
mutable int var;
public:
int GetX1()
{
return m_X1;
}
int GetX() const
{
//var是一个mutable变量,在const方法中可以修改它
var = 3;
return m_X;
}
void SetX(int x)
{
m_X = x;
}
};
void PrintEntity1(const Entity* e)
{
e = nullptr;//允许编译,允许指向其他
//(*e).SetX(2);//报错,不允许修改值
std::cout << (*e).GetX() << std::endl;
}
void PrintEntity2(const Entity& e)
{
//e = nullptr;//不允许编译,因为是引用,不允许重新指向其他
//e.SetX(2);//报错,不允许修改值
std::cout << e.GetX() << std::endl;
//不允许调用非const修饰的函数,下面会报错,
//因为无法保证GetX1()是否修改了e,而e是const修饰的
//std::cout << e.GetX1() << std::endl;
}
int main()
{
std::cin.get();
}
mutable#
class成员变量#
#include <iostream>
#include <string>
class Entity
{
private:
std::string m_Name;
//允许标记为const的方法修改该变量
mutable int m_DebugCount = 0;
public:
//1.如果是 const std::string,则返回的是一个副本
//返回一个引用
//2.最后的const表示该函数内部不允许修改类的非static成员变量
const std::string& GetName() const
{
//m_Name = "a";//非法
m_DebugCount++;//编译通过
//由于返回的是引用,所以这里返回了成员变
//量 m_Name 的一个“地址”或“别名”
return m_Name;
}
void MyTest()
{
}
};
int main()
{
const Entity e;
e.GetName();//调用const方法
//e.MyTest();//不允许调用非const方法
Entity e1;
e1.GetName();//调用const方法
e1.MyTest();//调用非const方法
std::cin.get();
}
lambda表达式中#
#include <iostream>
int main()
{
//lamda表达式
int x = 1;
int y = 8;
const int z = 5;
//按引用捕获所有变量
auto f1 = [&]()
{
y = 3;//合法,和原变量一样
//z = 5;//不合法,和原变量一样是const
std::cout << "Hello" << std::endl;
};
//mutable 不能直接修饰普通的局部变量或全局变量,只能
//是类成员变量
//mutable int m2 = 0;//没这种写法,会报错
//按值捕获所有变量
auto f2 = [=]()
{
//y = 3;//不合法,默认是const
std::cout << "Hello" << std::endl;
};
//按值捕获所有变量
//默认情况下,Lambda 内部的 operator() 是 const 的,不允
//许修改捕获的副本。加上 mutable 后,Lambda 内部就可以修改这些副本了。
auto f2_1 = [=]() mutable
{
y = 3;
std::cout << "Lambda 内部 y = " << y << std::endl;//3
};
std::cout << "外部原变量 y = " << y << std::endl;//8
//按值捕获x变量
auto f3 = [x]()
{
//y = 3;//不合法,默认是const
std::cout << "Hello" << std::endl;
};
f1();
f2();
f3();
std::cin.get();
}