引言:const是一个C++语言的限定符,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性。另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。
1. 修饰常量
用const修饰的变量是不可变的,以下两种形式是一样的。
const int nValue = 9;
int const nValue = 9;
2. 修饰指针
- 如果const位于*的左边,那么const修饰的是指针所指向的变量,也就是变量为常量,不可变。但是指针所对应的地址可以修改。
- 如果const位于*的右边,那么const修饰的是指针本身,也就是指针本身是常量,指向的地址不可变,但是值可以修改。
int const * p 和 const int * p 是一样的,但是使用上倾向于后者,这样更容易理解。
int nValue = 9;
const int * p = &nValue; // const修饰的是变量,也叫作常量指针(指向常量的指针)
int * const p = &nValue; // const修改的是指针,也叫作指针常量(常量是指针)
const int * const p = &nValue; // 变量和指针都是常量。
如果这样看可能更容易理解下:
- const int * p: const修饰的是* p,而* p代表的是变量,所以修饰的是变量。
- int const * p; const修饰的是p,而p代表的是变量的地址,也就是指针本身。
3. 修饰引用
以下两种定义形式在本质上是一样的:
int a = 10;
const int& b = a;
int const& b = a;
4. 修饰函数参数
用const修饰函数参数,传递过来的参数在函数内不可以改变。
void func (const int& n)
{
n = 10; // 编译错误
}
5. 修饰函数返回值
用const修饰函数返回值的含义和用const修饰普通变量以及指针的含义基本相同。
const int * func() // const修饰的是*func(),是变量,所以返回的指针所指向的内容不能修改
{
// return p;
}
int * const func() // const修饰的是func(),是指针,所以返回的指针不能修改
{
// return p;
}
6. 修饰类成员变量
用const修饰的类成员变量,只能在类的构造函数初始化列表中赋值,不能在类构造函数体内赋值。
class A
{
public:
A(int x) : a(x) // 正确
{
//a = x; // 错误
}
private:
const int a;
};
7. 修饰类成员函数
用const修饰的类成员函数,在该函数体内不能改变该类对象的任何成员变量, 也不能调用类中任何非const成员函数。
const在函数名后面表示是类的常成员函数,该函数不能修改对象内的任何成员,只能发生读操作,不能发生写操作。
class A
{
public:
int& getValue() const
{
// a = 10; // 错误
return a;
}
private:
int a; // 非const成员变量
};
8. 修饰类对象
用const修饰的类对象,该对象内的任何成员变量都不能被修改。因此不能调用该对象的任何非const成员函数,因为对非const成员函数的调用会有修改成员变量的企图。
class A
{
public:
void funcA() {}
void funcB() const {}
};
int main
{
const A a;
a.funcB(); // 可以
a.funcA(); // 错误
const A* b = new A();
b->funcB(); // 可以
b->funcA(); // 错误
}
9. 在类内重载成员函数
class A
{
public:
void func() {}
void func() const {} // 重载
};
具体可以参考这里:https://www.cnblogs.com/qingergege/p/7609533.html
10. const与宏定义的区别
const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误。
const常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
另外,编译器通常不为const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
#define PI 3.1415926535
const double PI = 3.1415926535;
11. const_cast
const_cast运算符用来修改类型的const或volatile属性。
- 常量指针被转化成非常量的指针,并且仍然指向原来的对象;
- 常量引用被转换成非常量的引用,并且仍然指向原来的对象。
void func()
{
const int a = 10;
int* p = const_cast<int*> (&a);
*p = 20;
std::cout<<*p; // 20
std::cout<<a; // 10, 原因见第10部分
}