const修饰变量
const的作用是:在编写程序过程中,因为我们会调用各种函数,假如我们并不想让某个已经赋了初值的变量在程序运行过程中受到改变,因此我们用const来作为关键字来修饰。
定义格式:const+typename+变量名:const int a;或者是typename+const+变量名:int const a
如果我们尝试想要改变const定义的变量值的话,会出现
另外const作用于变量最常用的是引用的方法:
#include<iostream>
int main()
{
int a = 4;
const int &b = a;
int& c = a;
b = 5;//编译器报错,表达式必须是可修改的左值
c = 5;//正确;
}
在上述代码中,b是a的一个引用,可是我们并无法通过b来改变a的值(因为被定义成了const),而c则可以,我们可以通过改变c的值来改变a和b。在引用过程中const引用的对象b的值会随着引用的对象自身a或者是其他非const引用的对象c的改变而改变。
const用于指针注意事项:
const int*p意思为*p是不可改变的,p=&a是对的,但是*p=a报错;
int* const p意思是p是不可变的,*p=a是对的,但是p=&a报错;
const int*const p意思是无论*p或者是p都是不可变,上述俩全是错的。
const修饰函数
修饰函数参数:typename+函数名(const typename+参数名,const typename+参数名...)
这种方法多用于指针和引用的情况,防止指针或者是对象副本在函数里面被改变(如果是const int/char/double(内置) +参数名这种的话,用const意义不大,因为函数调用时是将实参复制成形参,对形参的操作影响不到实参(直接在函数内定义一个const int a=**更简单),所以没必要对这种类型的使用const)
在使用const作为参数时要注意传递的参数类型和const定义的参数是否类型相同:
注意:const类型定义的指针类型的参数传参时可以是非const或者是const;
非const类型定义的指针类型的参数传参时必须是非const。
#include<iostream>
int add(const int* a, const int* b)
{
return *a + *b;
}
int reduce(int* a, int* b)
{
return *a + *b;
}
int main()
{
const int x = 3;
int y = 5;
std::cout << add(&x, &y);
std::cout << reduce(&x, &y);//第一个参数&x报错
}
修饰函数返回值:
const作用于函数最前面,表示返回值不可以被更改,下例中c的地址是返回值,不可以被更改,但是让const int*p=c的地址,这同时让*p的值不可以被更改,之所以这样做是因为让返回值类型对照上。
多用于指针和引用方面,同时也需要注意返回值类型只能赋给带有const的同类型
#include<iostream>
const int* add(const int* a, const int* b)
{
static int c = *a + *b;
return &c;
}
int main()
{
const int x = 3;
const int y = 5;
//int* p = add(&x, &y);错误(活动) E0144 "const int *" 类型的值不能用于初始化 "int *" 类型的实体
const int* p = add(&x, &y);//true,这个const修饰的是*p
std::cout << *p;//8
}
当采用值传递的方法,函数会在返回之前将结果复制并放在一个临时的储存单元中,加不加const无意义。
#include<iostream>
const int add(const int* a, const int* b)
{
static int c = *a + *b;
return c;
}
int main()
{
const int x = 3;
const int y = 5;
const int q = add(&x, &y);//true
int p = add(&x, &y);//true
std::cout << q << " " << p;
}
const用于类
1.用于类的成员变量,成员变量值无法被修改,构造函数里面也不可出现const所定义的变量,可以在定义时候给出值。
#include<iostream>
int main()
{
class time
{
public:
time(int x=2,int y=4)
{
a = x;
b = y;//error 表达式必须是可被修改的左值
}
private:
int a;
const int b=2;
};
}
2.用于类的成员函数,注意这个成员函数只可以读,不可以写入,是在参数()后给出的const
#include<iostream>
class time1//time也可以是函数库里面的一个函数,在定义时time无法用作全局,会被识别成函数
{
public:
time1(int x = 2, int y = 4)
{
a = x;
b = y;//error 表达式必须是可被修改的左值
}
void print()const
{
std::cout << a << "::" << b<<std::endl;
//a++;//error 表达式必须是可被修改的左值
}
void print1()
{
std::cout << a << "and" << b;
}
private:
int a;
int b;
};
int main()
{
time1 q;
q.print();
q.print1();//普通对象可以调用const成员函数和普通函数;
}
3.常对象和mutable
常对象是指定义对象之后,其所以数据成员无法被修改(mutable定义的除外)。和const定义的普通变量一样,常对象在定义的同时必须初始化,注意:常对象只可以调用const的成员函数,不可以用普通成员函数;而普通对象可以调用const或者是普通的成员函数。
#include<iostream>
class time1//time也可以是函数库里面的一个函数,在定义时time无法用作全局,会被识别成函数
{
public:
time1(int x = 2, int y = 4)
{
a = x;
b = y;//error 表达式必须是可被修改的左值
}
void print()const
{
std::cout << a << "::" << b<<std::endl;
//a++;//error 表达式必须是可被修改的左值
}
void print1()
{
std::cout << a << "and" << b;
}
private:
int a;
int b;
};
int main()
{
const time1 p;
time1 q;
q.print();//true
q.print1();//普通对象可以调用const成员函数和普通函数;
p.print();//true
p.print1();// 错误(活动) E1086 对象含有与成员 函数 "time1::print1" 不兼容的类型限定符
}
如果真的想要修改常对象里面的数据成员,可以将其声明成mutable,这样就可以修改。mutable一般用于常对象,普通对象如果想要修改数据成员在不用mutable,在非常函数里面进行修改即可。
#include<iostream>
class time1//time也可以是函数库里面的一个函数,在定义时time无法用作全局,会被识别成函数
{
public:
time1(int x = 2, int y = 4)
{
a = x;
b = y;//error 表达式必须是可被修改的左值
}
void print()const
{
b++;//mutable声明的可以修改
std::cout << a << "::" << b<<std::endl;
//a++;//error 表达式必须是可被修改的左值
}
void print1()
{
std::cout << a << "and" << b;
}
private:
int a;
mutable int b;
};
int main()
{
const time1 p;
p.print();
}