本文已参与[新人创作礼]活动,一起开启掘金创作之路。
(欢迎大家关注我的微信公众号——控制工程研习,上面会分享很多我学习过程中总结的笔记。) 1. 两个一模一样的函数,一个使用const修饰,一个不使用const修饰,这两个函数可以进行重载吗?
答案: 可以的
分析:
举个例子:
#include<iostream>
using namespace std;
class Test
{
public:
Test(int v) :data(v) {}
void print()//this指针的类型是Test *
{
cout << "调用非const成员函数!" << endl;
}
void print() const//const Test* this
{
cout << "调用const成员函数!" << endl;
}
private:
int data;
};
void main()
{
Test a(5);
a.print();//将对象a的地址传给成员函数的this指针
const Test b(6);
b.print();//将常对象b的地址传给const成员函数的this指针
}
运行的结果是:
可以发现两个对象分别调用到了不同的成员函数,原因在于这两个对象一个是const修饰的,一个不是const修饰的。这说明两个一模一样的函数,一个使用const修饰,一个不使用const修饰,这两个函数是可以重载的。
那么用const修饰函数的作用是什么呢?这就涉及下一个面试题。
2. const修饰函数起到了什么作用?哪些变量不能修改?
答案:
将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在成员函数中不 能对类的任何成员进行修改。
分析:
这里再补充一些知识,可以通过实验验证:
(1)const对象不可以调用非const成员函数。
(2)非const对象可以调用const成员函数。
(3)const成员函数内不可以调用其它的非const成员函数。
(4)非const成员函数内可以调用其它的const成员函数。
可以发现,非const对象也能调用const成员函数,那么const成员函数的用处在哪里呢?
如果成员函数需要返回引用类型,那么设计两个相同的成员函数,一个const一个非const才是合理的。因为对于返回值是引用(reference)的情况来说,就有一些问题了。—— const成员函数虽然能让const对象和非const外部对象都访问,但是他的返回值为const_reference,却不是我们期望的,因为我们的非const对象我们是期望它能修改的其中元素的,而返回了const_reference类型,又无法修改元素。这就造成了效果和意图的矛盾.
3. const除了修饰函数,还可以修饰什么?
分析:
还可以修饰变量。变量中较难的就是指针变量。
当用 const 进行修饰时,根据 const 位置的不同有三种效果。原则是:修饰谁,谁的内容就不可变,其他的都可变。这三种情况在面试的时候几乎是必考的,在实际编程中也是经常使用的。
4. 顶层const和底层const的区别
分析:
首先需要知道什么是顶层const和底层const:
(1)指向常量的指针:代表 不能改变其指向内容的指针。声明时const可以放在类型名前后都可,拿int类型来说,声明时:const int和int const 是等价的。声明指向常量的指针也就是底层const。
例如:int const *p = &a;
注意:指向“常量”的指针不代表它所指向的内容一定是常量,只是代表不能通过解引用符(操作符*)来改变它所指向的内容。
(2)指针常量:代表指针本身是常量,声明时必须初始化,之后它存储的地址值就不能再改变。声明时const必须放在指针符号*后面,即:*const 。声明常量指针就是顶层const。
例如:int *const p = &a;
这样的区分有两个作用:
(1)执行对象拷贝时有限制,常量的底层const不能赋值给非常量的底层const。也就是说,你只要能正确区分顶层const和底层const,你就能避免这样的赋值错误。
(2)使用命名的强制类型转换函数const_cast时,需要能够分辨底层const和顶层const,因为const_cast只能改变运算对象的底层const。