系列文章目录
C++高性能优化编程系列
深入理解软件架构设计系列
高级C++并发线程编程
C++技能系列
期待你的关注哦!!!
生活就是上帝发给你的一张手牌,无论多烂,你都得拿着。
Life is god give you a hand, no matter how bad, you have to take.
const的几种使用
- 系列文章目录
- 一、声明带const
- 1、const int a
- 2、const int &a
- 3、const char *p & char const *p
- 4、char * const p
- 5、const char * const p & char const * const p
- 二、函数形参带const
- 1、函数形参带const的 - 使用
- 2、函数形参带const的 - 好处
- 三、成员函数末尾带const
- 四、const的克星mutable
- 五、小结
一、声明带const
1、const int a
(1)表示常量a,不能改变a的值
//不能改变p的值
const char p = 'f';
2、const int &a
(1)表示常量引用,a代表的内容不能修改
int i = 100;
const int &a = i; //表示a所代表的内容不能被修改
const int &b = 156; //可以,字面值初始化常量引用
int &c = 156; //错误
b = 157; //错误,b看成常量,值不能修改
3、const char *p & char const *p
(1)'char const *p;'等价于'const char *p;'
(2)表示常量指针(p所指向的内容不能通过p来修改):
char str[] = "I Love China";
char *p;
p = str;
*p = 'Y';
p++; //p可以指向不同的位置,只要这些位置的内存归我们管即可
如果将p的定义修改为:
const char *p; //表示常量指针(p所指向的内容不能通过p来修改)
*p = 'Y'; //错误
当然,通过str修改内容则没有问题:
str[0] = 'Y';
4、char * const p
(1)表示指针常量(p不可以指向其他内容):
看如下范例:
char str[] = "I Love China";
char * const p = str; //定义的时候必须初始化
p++; //这里不可以,p指向一个内容后,不可以指向其他内容(p不可以指向不同目标)
*p = 'Y'; //但可以修改指向的目标的内容
5、const char * const p & char const * const p
(1)'const char * const p;'等价于'char const * const p;'
(2)表示p的指向不能改变,p指向的内容也不能通过p来改变。
二、函数形参带const
1、函数形参带const的 - 使用
struct student {int num};
void fs(student &stu){
stu.num = 1010;
}
student abc;
abc.num = 100;
fs(abc);
std::cout << abc.num << std::endl; //1010
上面这段代码,可以注意到,在fs()函数中可以修改stu里的num成员,修改后,该值会被带回到主调函数中,也就是说,fs()函数中对形参stu的修改实际就是对实参abc的修改,因为这里形参采用的是引用类型。
如果不希望在函数fs中修改形参stu里的值,建议形参最好使用常量引用的习惯。
void fs(const student &stu){
stu.num = 1010; //这句就错误了,不能修改stu中的内容
}
再继续看范例:
void fs(const int i){ //实参可以是正常的int,形参可以使用const int接,这都没问题
i = 100; //这也不行,不能给常量赋值
}
2、函数形参带const的 - 好处
(1)可以防止无意中修改了形参值导致实参值被无意中修改掉。
(2)实参类型可以更加灵活。
struct student {int num};
void fs(student &stu){
}
student abc;
abc.num = 100;
const student& def = abc;
fs(def);//错误,因为def类型是const&,而函数fs的形参不带const
std::cout << abc.num << std::endl; //1010
如果改成:
void fs(const student &stu){
}
可以看到const student &stu这种类型的形参可以接受的实参类型更多样化,可以接收普通的引用作为实参,也可以接收常量引用作为实参。
再继续看看如下范例:
void func2(int &a);//定义函数func2()
func2(156);//不可以,必须传递进去一个变量
修改后:
void func2(const int &a);//定义函数func2()
func2(156);//可以,可以船进去一个常量
三、成员函数末尾带const
成员函数末尾加const
起什么作用呢?表示该成员函数不会修改该对象里面的任何成员变量的值。
这种在末尾加了一个const
的成员函数也称常量成员函数。
class Persion{
public:
void Get() const{
a_ += 10; //错误,常量成员函数不可以修改成员变量的值
}
void Add(int x){
a_ = a_ - x ;
}
private:
int a_;
}
从上面的代码看,如果在Get的成员函数中修改成员变量a_的值,是不被允许的。
看看如下范例:
// 定义const对象,这种对象有限制
const Persion per;
// 不可以,Add成员函数是非const的,只能被非const的对象调用
per.Add(14);
// 可以因为Get()的成员函数是const
per.Get();
Persion per2;
//Get是const成员函数,则不管是cosnt对象还是非const对象都可以调用const员函数
//而非const得成员函数不能被const对象调用,只能被非const对象调用
per2.Add();
总结一下:
(1)const成员函数,则不管是cosnt对象还是非const对象都可以调用const员函数。
(2)而非const得成员函数不能被const对象调用,只能被非const对象调用。
(3)普通函数(非成员函数)末尾是不能加const, 编译都无法通过。
四、const的克星mutable
mutable
,翻译成中文不稳定的、容易改变的意思。与const
正好是反义词。而且mutable的引入也正是为了突破const
的限制。
刚刚已经看到,在末尾有const
修饰的成员函数中,是不允许修改成员变量值的。那在设计类成员变量的时候,假如确实遇到了需要在const
结尾的成员函数中希望修改成员变量值的需求,怎么办呢?
也许有人会说,那就把函数末尾的const
去掉,变成一个非const
的成员函数。那就会引入一个新问题,如果这个成员函数从const
变成一个非const
的了,那么就不能被const
对象调用。
所以,引入了mutable修饰符(关键字)来修饰一个成员变量。一个成员变量一旦被mutable所修饰,就表示这个成员变量永远处于可变的状态,即使在以const结尾的成员函数中。
看如下范例:
class Persion{
public:
void Get() const{
a_ += 10; //可以修改成员变量a_了
}
void Add(int x){
a_ = a_ - x ;
}
private:
mutable int a_;
}
五、小结
开发中经常使用,面试中也是经常被问的,所以谨记于心。