C++面试题(2)| 进来看看你会回答吗

96 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

image.png

(欢迎大家关注我的微信公众号——控制工程研习,上面会分享很多我学习过程中总结的笔记。) 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。