前言
本文主要介绍const的各种用法,修饰变量、函数、函数返回值、对象等一系列的属性
const变量
const修饰指针
很简单的,大家也都记得const的很多属性,比如修饰值无法进行再次赋值,声明必须初始化,但是大家熟悉下面的用法吗?看代码
const int * a = nullptr;
int * const a = nullptr;
const int * const a = nullptr;
以上三种变量的区别吗?下面我们一个一个分析:
语句(1)中声明了一个常量指针(也叫“底层const”,根据命名,可以猜出是代表指针指向的是一个常量),所以其特性就是(1)无法通过解引用指针a来改变其指向的变量的值,但是仅仅代表无法通过指针来改变(2)一个非const变量可以直接赋值给const变量
语句(2)中声明了一个指针常量(根据命名,可以猜出是表示指针无法再次赋值)。
语句(3)语句结合了(1)(2)的特性,所以它也集成了指针常量和常量指针的所有特性。
const修饰引用
这一节我不在这里说了啊, 放在以后的复制构造函数相关的内容里说~
const函数
const修饰函数参数
void func(const int a)
{
a = 0;
}
编译器报错,因为a是一个const变量,这个很简单,跳过~
const修饰函数返回值
这部分也不展开了,和后面的拷贝构造函数一起说~
const修饰成员函数
class deived :public base
{
public:
int a;
public:
void func1();
void func2() const;
};
表示const成员函数不能修改任何其对象中的成员变量值,mutable修饰的变量除外
const对象
const修饰对象,这个还是上代码吧
class deived :public base
{
public:
int a;
public:
void func1();
void func2()const;
};
int main()
{
const deived _deived;
_deived.a = 0;
_deived.func1();
_deived.func2();
}
其中类deived中定义了一个非const成员函数func1(),和一个const成员函数func2(),然后main函数中定义了一个const对象_deived,通过_deived更改a的值并且调用func1和func2,好了,编译一下
报错了,告诉我们无法通过_deived来改变a的值,这个很好理解,毕竟const对象嘛,但是我们还是像上面一样,把变量声明为mutable的,还可以进行重新赋值吗?答案是肯定的~
接下来看说“this指针不能从const deived转换为deived &”,在《c++primer》书中说道:”指向常量的指针不能用于改变其所指对象的,要想存放常量对象的地址,只能使用指向常量的指针“,
也就是
int main()
{
const int* a = nullptr;
int* b = nullptr;
b = a; //报错,无法从const int *转换为 int *
a = b;//正确
}
估计这里有些人也就有点晕了,我靠,为啥b可以给a赋值,a不能给b赋值。
我们从语言的角度想一下,a是一个常量指针,我们上面说过“无法通过指针来修改其对象的值”,所以如果c++支持常量指针能够赋值非常量指针,那么它这条属性还有存在的必要吗?哈哈
那么为啥非常量指针能给常量指针赋值呢,因为它是非常量指针,它没有那么多条条框框,你愿意改你就改,你不改也随便你,哈哈,这样是不是就很容易理解了~
好,再回到我们刚才的问题,说“this指针不能从const deived转换为deived &”,嗯,还是这个道理,如果支持const deived&转换成deived&,那这个底层const还有存在的必要吗?所以无法这样转换的,自然也就得出我们的结论:const对象无法直接访问到非const成员函数,为啥我要强调这个直接访问几个字呢?嘿嘿,感兴趣的童鞋可以自行研究一下。
好了,本文到这里就结束了,再见各位~