const的用法
以前看文章都说const修饰变量代表着“只读”,而自己却对const和指针混合修饰变量时常常搞混,今天就来通过代码探讨const的用法。
1. const修饰普通变量(有以下两种写法)
const TYPE value;
TYPE const value;
这两种写法在本质上是一样的。都表示:const修饰的类型为TYPE的变量 value 是不可变的。
2. const修饰指针类型的TYPE
A:const char *pContent; // 对其加上括号为:const (char) *pContent; A和B效果相等
B:char const *pContent; // 对其加上括号为:(char) const *pContent; A和B效果相等
C:char * const pContent; // 对其加上括号为:(char) * const pContent;
D:const char * const pContent;
对于A,B,const修饰的是 (*pContent)。其中 pContent为指向char类型的指针,*pContent则表示该指针指向内存空间里的值。既然const修饰的是 (*pContent),也就是说指针pContent指向的内容值为常量,不能修改,但是pContent指针可以修改。(以下通过函数解释说明)
1 #include <stdio.h>
2
3 int main()
4 {
5 char a = 5, b = 6; // 定义两个char变量
6 const char *pContent; // 定义一个char类型的指针
7
8 pContent = &a; // 指针pContent指向a的地址,此时*pContent=5
9 printf("*pContent = %d\n", *pContent);
10
11 pContent = &b; // 把指针pContent重新指向b的地址,编译运行都OK,此时*pContent=6
12 printf("*pContent = %d\n", *pContent);
13
14 (*pContent)++; // 试图让(*pContent)的值加1,此处编译出错,因为(*pContent)的值不能修改
15 printf("*pContent = %d\n", *pContent);
16 return 0;
17 }
对于【char * const pContent】,const修饰的是指针pContent,所以指针pContent指向的地址不能修改(既然pContent指向的地址不能修改,所以要求定义时需要初始化),但是指针pContent指向的地址里的值可以修改。(以下通过函数解释说明)
1 #include <stdio.h>
2
3 int main()
4 {
5 char a = 5, b = 6; // 定义两个char变量
6 char * const pContent = &a; // 定义一个char类型的指针,并初始化指向a的地址
7 printf("*pContent = %d\n", *pContent); // 输出 *pContent = 5
8
9 (*pContent)++; // 让(*pContent)的值加1,编译运行都OK
10 printf("*pContent = %d\n", *pContent); // 输出 *pContent = 6
11
12 pContent = &b; // 试图修改指针pContent指向b的地址,此处编译出错,因为指针pContent不可变
13 printf("*pContent = %d\n", *pContent);
14
15 return 0;
16 }
当然,D则是A,C或者B,C的组合了。此处就不在做代码演示。
const的拓展
1. const修饰类对象,类成员函数和类成员变量
(1)const修饰类的成员函数,则该成员函数不能修改该类的内容(如类的成员变量的值)
(2)const修饰类的对象,则表示该对象为常量对象,类中的任何成员都不能被修改。const修饰的对象,该对象只能调用该类的const类型的函数,非const类型函数不能调用,因为任何非const成员函数会有修改成员变量的企图。
1 #include <iostream>
2
3 using namespace std;
4
5 class Student
6 {
7 public:
8 int m_dwAge;
9 public:
10 Student();
11 ~Student();
12 // func1()能修改Student的内容(如修改m_dwage的值)
13 void func1(int a) { m_dwAge = a; cout << ++a; }
14 // func2()被修饰为const了,所以不能修改Student的内容(如以下追加m_dwAge = b;则编译通不过。)
15 void func2(int b) const { cout << ++b; }
16 };
17
18 Student::Student() { m_dwAge = 0; }
19
20 Student::~Student() {}
21
22 int main()
23 {
24 const Student stu; // 定义一个不能修改Student的对象stu
25 stu.func2( 5 ); // 因为func2()已经被const修饰过了,确保了Student不会被修改,所以此处编译能通过
26 stu.func1( 8 ); // 因为func1()没有被const修饰过,所以fun1有修改Student的企图和能力,所以此处编译出错
27 return 0;
28 }
(3)const修改类的成员变量,表示成员变量不能被修改,同时他只能在初始化列表中赋值。
class Student
{
public:
const int m_age; // 成员变量不能被修改
……
Student(int age) : m_age(age) {}; // 只能在初始化列表中赋值
}
};
2. const常量与define宏定义的区别
(1)编译器处理方式不同:
define宏是在预处理阶段展开。
const常量是编译运行阶段使用。
(2)类型和安全检查不同:
define宏没有类型,不做任何类型检查,仅仅是展开。
const常量有具体的类型,在编译阶段会执行类型检查。
(3)存储方式不同
define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。
const常量会在内存中分配(可以是堆中也可以是栈中)。