c++中的 const 关键字
知识回顾:C语言中 const
const 修饰的变量是 只读的,本质上还是变量;(只读变量:可以通过指针修改只读变量中的值)
const 修饰的局部变量在栈上分配空间;
const 修饰的全局变量在只读存储区分配空间;
const 只在编译期间生效,在运行期间无效;
const 修饰的变量不是真的常量,它只是告诉编译器该变量不能出现在赋值符号的左边;
1 #include <stdio.h> 2 3 int main() 4 { 5 const int c = 10; // c 是只读变量 6 int* p = (int*)&c; 7 8 *p = 5; 9 10 printf("c = %d\n", c); // c = 5 11 12 return 0; 13 } 14 // 编译器 gcc
c++ 中 const
1. const 常量
1)const 修饰的变量 是一个真正的常量;
这是由于c++中使用的符号表机制,当使用一个字面量初始化const变量时,就会将该字面量放入符号表中;在编译过程中,若发现使用该变量,就会将这个变量替换为符号表中值;
2)在编译过程中,若发生以下情况,则可能会给对应的常量分配存储空间;
1、当 const 常量为全局时,并且需要在其它文件中使用;(extern)
2、当使用 & 操作符对 const 常量取地址;
注:c++ 编译器虽然可能为 const 常量分配存储空间,但不会使用其存储空间中的值;
1 #include <stdio.h> 2 3 int main() 4 { 5 const int c = 10; // c 是常量 6 int* p = (int*)&c; 7 8 *p = 5; 9 10 printf("c = %d\n", c); // c = 10 11 12 return 0; 13 } 14 15 // 编译器 g++
3)const 常量 与 宏定义
相同点:
c++中 const 常量 ≈ 宏定义;( const int a = 10; ≈ #define a 10 )
不同点:
const 是由编译器处理,编译器对 const 有 类型检查 和 作用域检查;
宏定义 是由预处理器处理,只是单纯的文本替换;
1 #include <stdio.h> 2 3 void f() 4 { 5 #define a 3 6 const int b = 4; 7 } 8 9 void g() 10 { 11 printf("a = %d\n", a); 12 //printf("b = %d\n", b); // err 13 } 14 15 int main() 16 { 17 const int A = 1; 18 const int B = 2; 19 int array[A + B] = {0}; 20 int i = 0; 21 22 for(i=0; i<(A + B); i++) 23 { 24 printf("array[%d] = %d\n", i, array[i]); 25 } 26 27 f(); 28 g(); 29 30 return 0; 31 }
结论:--- 经典问题解析一
1)const 常量的判断方法:
1、只有用 字面量初始化的 const 常量才会进入符号表;
2、使用其它变量初始化的 const 常量仍然是 只读变量;
3、被 volatile 修饰的 const 常量不会进入符号表;
2)const 引用类型 与 初始化变量的类型
相同:初始化变量成为只读变量;
不同:生成一个新的只读变量;
1 #include <stdio.h> 2 3 int main() 4 { 5 const int x = 1; // 只有用 字面量 初始化的const常量才进入符号表--- 此处x进入符号表,x是常量 6 const int& rx = x; // 编译器分配给常量x的内存地址的别名为 rx--- rx是只读变量 7 8 int& nrx = const_cast<int&>(rx); // 去除只读变量rx的只读属性 --- nrx 9 10 nrx = 5; 11 12 printf("x = %d\n", x); // 1 13 printf("rx = %d\n", rx); // 5 14 printf("nrx = %d\n", nrx); // 5 15 printf("&x = %p\n", &x); // 0x7ffd8aed8f90 16 printf("&rx = %p\n", &rx); // 0x7ffd8aed8f90 17 printf("&nrx = %p\n", &nrx); // 0x7ffd8aed8f90 18 19 volatile const int y = 2; // volatile 修饰的const常量不会进入符号表---y是只读变量 20 int* p = const_cast<int*>(&y); // 去除y的只读属性 21 22 *p = 6; 23 24 printf("y = %d\n", y); // 6 25 printf("&y = %p\n", &y);// 0x7ffd8aed8f94 26 printf("p = %p\n", p); // 0x7ffd8aed8f94 27 28 const int z = y; // 用 其它变量 初始化const常量,仍是只读变量 --- z是只读变量 29 30 p = const_cast<int*>(&z); // 去除z的只读属性 31 32 *p = 7; 33 34 printf("z = %d\n", z); // 7 35 printf("&z = %p\n", &z);// 0x7ffd8aed8f98 36 printf("p = %p\n", p); // 0x7ffd8aed8f98 37 38 char c = 'c'; 39 char& rc = c; 40 const int& trc = c; //const引用类型 与 初始化变量的类型不一致,则生成新的只读变量 --- trc为新的只读变量 41 42 printf("c = %c\n", c); // c 43 printf("rc = %c\n", rc); // c 44 printf("trc = %c\n", trc); // c 45 46 rc = 'a'; 47 48 printf("c = %c\n", c); // a 49 printf("rc = %c\n", rc); // a 50 printf("trc = %c\n", trc); // c 51 52 return 0; 53 }
3) 指针常量 Type * const pt (引用的本质)
c++中没有引用数组的概念;(因为数组在内存中是一段连续的存储空间,然而引用数据并不满足这个要求)
2 类中的 const(const 对象 和 const 成员函数)--- 经典问题解析二
const 对象的特点:
1)const修饰的对象为只读对象;
2)只读对象的成员变量不可以修改;
3)只读对象是编译阶段的概念,运行时无效;
注:const 对象 不推荐使用;
const 成员函数的特点:
1)只读对象只能调用const成员函数;
2)const成员函数 只能 调用const成员函数;
3)const成员函数 不能 直接修改成员变量的值;(const 成员函数 使 this指针所指向的对象具有了只读属性)
注:const 成员函数 在 声明与定义的时候必须都有 const;
1 #include <stdio.h> 2 3 class Test 4 { 5 int mi; 6 public: 7 Test(int i); 8 Test(const Test& t); 9 int getMi() const; 10 void print(); 11 }; 12 13 Test::Test(int i) 14 { 15 mi = i; 16 } 17 18 Test::Test(const Test& t) 19 { 20 21 } 22 23 int Test::getMi() const 24 { 25 //mi = 0; // error // const成员函数 不能 直接修改成员变量的值 26 //print();// error // const成员函数 只能 调用const成员函数 27 return mi; 28 } 29 30 void Test::print() 31 { 32 printf("v = %d\n", mi); 33 } 34 35 int main() 36 { 37 /* 38 * 1 const可以修饰类的对象 39 * 2 const修饰的对象为只读对象 40 * 3 只读对象的成员变量不可以修改 41 * 4 只读对象是编译阶段的概念,运行时无效 42 */ 43 /* 44 * 1 只读对象只能调用const成员函数 45 * 2 const成员函数 只能 调用const成员函数 46 * 3 const成员函数 不能 直接修改成员变量的值 47 */ 48 const Test t(1); 49 printf("v = %d\n", t.getMi()); // 只读对象只能调用const成员函数 50 51 52 return 0; 53 }