const的最简单的用法,是定义程序用到的数字、字符串常量,代替宏定义。
const int MAX_LEN = 1024; const std::string NAME = "xixi";
和宏定义的本质区别是:const定义的常量在预处理阶段并不存在,而是直到运行阶段才会出现。所以,准确地说,它实际上是运行时的“变量”,只不过不允许修改,是“只读”变量
但是既然是变量,通过使用指针地址,再强制写入也是可以的,但这种做法破坏了常量性
const volatile int MAX_LEN = 1024; auto ptr = (int*)(&MAX_LEN); *ptr = 2048; cout<const后面需要加上volatile:因为const常量在大多数情况下被认为是常数,在运行期间不会改变,编译器看到const定义,就会采取一些优化手段,比如把所有const常量出现的地方都替换成原始值,所以对于没有volatile修饰的const常量来说,虽然用指针改了常量的值,但这个值在运行阶段根本没有用到,因为在编译阶段就被优化掉了
volatilevolatile:不稳定的易变的,在C++里表示变量的值可能会以难以察觉的方式被修改,比如操作系统信号,外界其他的代码,所以要禁止编译器做任何形式的优化,每次使用的时候都去取值。举例上述的MAX_LEN虽然是const变量但加上volatile表示它可能会被改变,编译器在生成二进制机器码的时候就不会再去做那些有可能副作用的优化即不会再把MAX_LEN替换成1024,而是每次都是去内存里面拿,但这个时候内存里的值已经通过指针被强制修改了。(const其实让编译器做更好的优化)
基本的const用法
而volatile会禁止编译器做优化。一般少用在C++里,除了最基本的值类型,还有引用类型和指针类型,它们加上const就成了常量引用和常量指针const&被称为万能引用,可以引用任何类型,不管是值、指针、左引用还是右引用,加上const特性,变量就变成常量,只能读,禁止写。编译器会检查所有对它的写操作。
const作用于指针有两种情况:
const放在最左边,下边举例:**const修饰的是string * p1,修饰的是指针指向的值,**代表指向的是一个“只读变量”,指向的变量不允许被修改string name = "xixi"; const string* p1 = &name; *p1 = "haha";//errror第二种是const放在*的右边,const修饰的是p2,是那个指针,指针不能被修改,但是指向的变量是可以被修改的
string* const p2 = &name; *p2 = "haha";//ok与类相关的const用法const成员函数
class DemoClass final { private: const long MAX_SIZE = 256; int m_value; public: int get_value() const//const成员函数 { return m_value; } };const放在函数前面表示返回值是const int, 现在放在函数后面,表示函数的执行过程是const的,不会修改对象的状态,即这个成员函数是一个“只读操作”;因为常量引用 常量指针关联的对象是只读不可修改的,那么调用它的函数也必须是不会修改他的,因此编译器会检查conts对象相关的代码,如果成员函数不是const就不能调用
ps:成员函数有一个隐含的this参数,所以语义上来说,const成员函数时加上是传入一个const this指针,但以为C++语法限制,无法声明const this,就把const放到了函数后面
依据应用场景,优的成员函数可能即是const又是非const,所以就会有两种重载形式
mutablevolatile可以用来修饰任何变量,而mutable只能修饰类里面的成员变量,表示变量即使在const对象里,也是可以被修改的。
即,const成员函数可以改写mutable成员变量class Democlass final { private: mutable mutex_type m_mutex;//mutable成员变量 public: void save_data() const//const成员函数 可以改写mutex {} };



