const 修饰用法
const 的用法 一句话:限定某个内容对应的值不可以被改变(是常量,不可再次被赋值!)
在C++11之前,有两个功能。
修饰常量 :定义变量时使用 把变量变为常量
变量只读 :函数形参处使用 表示形参为只读变量
这两者是有差别的!!!!!!
1 、const 于变量
1.1 int const 与const int
int const a = 100;
const int a = 100; //与上面等价
int const arr [3] = {1,2,3};
const int arr [3] = {1,2,3};//与上面等价
const 在数据类型 int 的左侧和在右侧是一样的
另外,int 也可以看做是一种类,a可以看做是对象。所以,const也可以修饰对象和结构体等数据
1.2 const修饰后成为常量,不可以再次被复制
int c1=10;int c2=20;
const int *p1=&c1;//p1对应的地址,其地址空间里的数据值固定
qDebug()<<"*p1="<<*p1<<endl;//输出值 10
*p1=c2;//error
p1=&c2;//改变地址,地址对应的值也就变了
qDebug()<<"*p1="<<*p1<<endl;//输出值 20
*p1=30;//error
//总之 *p1=常量 就是不被允许的
//*p=30;本质上是想改变地址空间里存储的数据值
总之 *p1=常量 的赋值操作 就是不被允许的
const int num =10;num=20;是错的。此时num是常量!是常量!是常量!10=20;这样的语句显然错误
同理 const int *p=#之后,无论p里面存储的地址值是多少,*p的值可以随地址改变而改变,但*p的结合 依旧是常量,不可再次被赋值。 *p=20;是错误的。
2.const 于指针变量(地址)
int a = 5; int b = 10;
int *const p = &a;
*p = 20; //right 可以修改所指向变量的值
p = &b; //error 不可以指向别的变量
此时 p与变量a的地址绑定,
3. const修饰函数
const 在函数中根据修饰的位置分为三种:函数参数、函数返回值、成员函数。
const int fun (const int a) const;
3.1 const 修饰 函数参数
3.1.1防止传入的变量被函数改变 比如指针的指向(地址存储的值)
char a='A',b='B';
char *str1=&a; char *str2=&b;
void stringCopy(char* strDest, const char* strSource);//函数声明
StringCopy(str1, str2);//函数调用 *str1 的值可以被函数改变 *str2的不能被改变
/*
此时 发生形参初始化的动作 char* strDest= str1;const char* strSource=str2;
strDest与 str1 对应的地址相同 strSource与str2
如果函数里面发生 * strDest='C';//操作合法,但是上面的*str1 的值发生了改变 即a='C'
如果函数里面发生 * strsOURSE='D';//操作报错 *str2的值,在函数里面改不了
*/
注意:const char* strSource作形参 之后,* strSource就不能再被赋值了,即不能被修改了。可以使用传入参数的值,但不能改变输入参数的值。防止传入值被函数改变
3.1.2修饰函数参数 传入值的问题
int add1(int& a, int& b){ //非const引用只能接受 变量,不能接受const类型的参数
return a + b;
}
int add2(const int & a, const int &b){
return a + b;
}
int main(int argc, const char * argv[]) {
int _a = 3;
const int _b = 5;
int _c = 4;
add1(_a,_a);//传入非const参数可以
add1(_a,_b);//传入const参数报错
cout << add2(_a,_b) <<endl;//const类型参数可以传入
cout << add2(_a,_c) <<endl;//非const类型参数可以传入
}
注意:const in &b作形参 之后,b就不能再被赋值了,是只读变量,即不能被修改了。可以使用传入参数的值,但不能改变输入参数的值。防止传入值被函数改变
3.2 const 修饰 成员函数 即 函数尾部的 const
class MyClass {
public:
void func(int x) const;
};
注意:const 放在函数尾部 这种情况仅限于函数是成员函数 !!!其它函数没这种修饰
1) const 成员函数与对象、函数、成员变量之间的关系
总结就是:
const 对象通过对象调用只能显式访问const 成员函数;非const 对象能所有显式成员函数;
const 成员函数能读取所有成员变量,但都不能修改它们;
const 成员函数只能访问const 成员函数,但能被其它任何成员函数访问;
const 修饰的成员函数为了保护成员变量,要求const 函数不能修改成员变量,否则编译会报错,除非变量用mutable修饰。
2) 函数尾部的const与函数重载:
函数尾部的有无const可以作为重载条件。例如,常对象调用同名函数时,一定是调用const函数。
需要注意的是,常对象的成员函数(除了常量成员函数)默认是不能修改成员变量的,因为被声明为常对象的成员函数是隐式的const
函数。如果在成员函数内部需要修改成员变量,可以使用mutable
关键字修饰相应的成员变量。
3.3 const 放在函数前
使用较少,略。
4.const 与引用
4.1普通变量的引用加const
int num =2;
const int& b=num;
num=3;
//b=4;//错误
cout<<"b="<<num<<endl;//b值为3
常引用必须在定义时,就初始化
const int& b;//错误,没初始化
b=4;//错误,不可再赋值
2023-07-16更新,未完待续,优化中……
const关键字的作用很多,这里只解释它作为函数形参的一个作用,主要有两个作用:
(1)它告诉编译器,这个参数是一个常量,首先你在函数内部不能改变它;
(2)其次,如果在函数内部需要多次引用这个值,CPU不必每次都重新读取,直接使用第一次读取的值(我想应该是存放在寄存器文件中的)。
常量表达式函数
使用constexpr修饰函数的返回值,这种函数被称为常量表达式函数。这些函数主要有以下几种:
普通函数
类的成员函数
类的构造函数
成员变量a变成了常量,不可再给它赋值了
模板函数 (函数模板是模板,如下面的10-13行。模板函数是函数模板定义出来的函数19,23行)