目录
const作用
(1)用来修饰变量、函数参数、返回值等,被const修饰的东西都会受到强制保护,能够防止被修改,提高了程序的健壮性。
(2)能够增强代码的可读性。
const用法
1.修饰普通变量
const修饰普通变量被叫做常量,定义的时候必须初始化。
实例:在C++中const修饰的变量c是一个常量,会被放到一个符号表中,并没有给变量c分配空间,只有当变量被别的文件调用或者被指针间接访问时才会分配空间,但是分配空间里面的值和常量c不是同一个,所以通过指针间接修改值并不是影响到符号表里面的常量c;但是在C语言中会修改到,因为在C语言中定义的const常量是一个伪常量,可以通过指针间接修改
int main()
{
int a = 1;
//const int b; //错误: const变量必须要初始化
const int c = 2; //正确:局部变量,分配在栈上
const int d = a; //正确
int* p =(int*) &c; //定义一个指针指向常量c
cout << "第一次" << *p <<" " << a << endl;
*p = 20; //修改指针所指向的内容,看能否修改常量c对应的值
cout << "第二次" << *p <<" " << a << endl;
system("pause");
}
2.修饰指针
(1)常量指针
实例:A的读法(从内到外):A是一个指针,指向一个int型对象,该对象是个常量。因此这是一个底层const;指针的指向可以修改,指针指向的内容不能修改。
int main()
{
int a = 1;
int b = 2;
//1和2是一样的
const int* A = &a; //1
//int const *A = &a; //2
//*A = 3; // 错误:指针指向的内容不能修改
A = &b; //指针的指向可以修改
system("pause");
}
(2)指针常量
实例:A的读法(从内到外):A是一个常量,这个常量是一个指针,指向一个int对象。因此这是一个顶层const;指针指向的内容可以修改,指针的指向不能修改。
int main()
{
int a = 1;
int b = 2;
int* const A = &a;
*A = 3; // 指针指向的内容可以修改
//A = &b; //错误: 指针的指向不能修改
system("pause");
}
(3)指向常量的常指针
实例:指针的指向不能修改,指针指向的内容不能修改
int main()
{
int a = 1;
int b = 2;
const int* const A = &a;
//*A = 3; //错误 指针指向的内容不能修改
//A = &b; //错误 指针的指向不能修改
system("pause");
}
记法:看const在 * 的前面还是后面 , const后面如果是 * ,那么就是常量指针,那么变量 取* 的操作就不可以(也就是修改指针变量的值);const后面如果是变量,那么就是指针常量,那么变量对应的操作就不可以(也就是修改指针指向)。
3.修饰函数参数
const修饰函数参数是为了防止在函数体内修改到参数原始对象。
(1)值传递
值传递是传递一份参数的拷贝给函数,并不会影响到原始对象,所以没必要将参数声明为const
1和2是相同意思的
//1
void func(int a);
//2
void func(const int a);
(2)指针传递
指针传递只会进行浅拷贝,拷贝一份指针给函数,而不会拷贝一份原始对象。给指针参数加上顶层const可以防止指针指向被修改,加上底层const可以防止指向内容被修改。
void func(int* a);
//参数为指针常量(顶层const)
void func(int* const a);
//参数为常量指针(底层const)
void func(const int* a);
(3)引用传递
引用传递不需要拷贝对象,因为引用就是对象的一个别名,可以减少开销,但是也导致可以通过修改引用直接修改原始对象。
void func(int& a);
void func(const int& a);
4.修饰函数返回值
(1)修饰普通类型的返回值
因为返回的临时变量本身就具有常性,所以这样的写法是没有必要的。
const int func(XXXXX);
(2)修饰指针类型的返回值
const int* func(XXX);
const int* p = func(XXX); //正确
int* p1 = func(XXX); //错误,
func是一个const int* 指针,不能修改指针所指向的内容,p1是非const指针,能够通过指针修改其所指向的内容,会导致访问权限放大,所以不能这样调用。
int* const func(XXX);
int* const p = func(XXX); //正确
int* p1 = func(XXX); //错误
(3)修饰引用类型的返回值
int& func(XXX);
const int& func(XXX);
int& const func(XXX);
5.修饰类成员
(1)修饰成员变量
表示成员变量不能被修改,同时只能在初始化列表中赋值。
(2)修饰成员函数
const修饰的成员函数叫作const成员函数。如果需要在const成员函数中修改成员变量的值的话,需要在成员变量前面加上mutable关键字。格式:const放在函数括号后面
(3)修饰类对象
对象的任何成员都不能被修改,const类对象只能调用const成员函数。
实例:
class A
{
public:
void func()const
{
cout<<b<<endl;
}
//该成员函数实际上是这样
/*
void func(const A*const this)
{
cout<<this->b<<endl;
}*/
void func1() const
{
b++;//错误
c++;//正确,加入mutable之后,能够在const成员函数中修改成员变量的值
}
private:
int b;
const int a;
mutable int c;
};
总结
(1)只要成员函数不修改调用对象,就应该将其声明为const,这样既可以避免调用对象被修改,而且普通对象和const对象都可以调用。如果需要在const成员函数中修改成员变量的值的话,需要在成员变量前面加上mutable关键字
(2)const对象只能调用const成员函数,不能调用非const成员函数;非const对象两者都可以调用。
(3)const成员函数只能调用类的const成员函数,不能调用非const成员函数;非const成员函数两者都可以调用。
(4)const成员函数能够访问const成员,非const成员函数不能访问const成员。
(5)const不能和static一起使用,因为static修饰成员函数时,静态成员函数不含this指针,也就是不能实例化,但是const成员函数必须具体到某一个实例上。
(6)构造函数不能声明为const,因为const成员函数不能修改成员变量,但是构造函数需要修改类的成员变量。