C++岗位求职面试八股文第八篇

系列文章目录

第一篇:语言基础
第二篇:设计模式
第三篇:数据库
第四篇:计算机网络
第五篇:操作系统
第六篇:LInux
第七篇:数据结构
第八篇:智力题

[141]析构函数能抛出异常吗 不能·(释放资源了,不会抛出)

如果对象在运行期间出现了异常,C++异常处理模型有责任清除那些由于出现异常所导致的已经失效了的对象(也即对象超出了它原来的作用域),并释放对象原来所分配的资源, 这就是调用这些对象的析构函数来完成释放资源的任务,所以从这个意义上说,析构函数已经变成了异常处理的一部分。

[142]模板类是在什么时候实现的

模板实例化:模板的实例化分为显示实例化和隐式实例化,前者是研发人员明确的告诉模板应该使用什么样的类型去生成具体的类或函数,后者是在编译的过程中由编译器来决定使用什么类型来实例化一个模板不管是显示实例化或隐式实例化,最终生成的类或函数完全是按照模板的定义来实现的

模板具体化:当模板使用某种类型类型实例化后生成的类或函数不能满足需要时,可以考虑对模板进行具体化。具体化时可以修改原模板的定义,当使用该类型时,按照具体化后的定义实现,具体化相当于对某种类型进行特殊处理。

[143]类继承时,派生类对不同关键字修饰的基类方法的访问权限

类中的成员可以分为三种类型,分别为public成员、protected成员、private成员。
类中可以直接访问自己类的public、protected、private成员,但类对象只能访问自己类的public成员。

public继承:派生类可以访问基类的public、protected成员,不可以访问基类的private成员;
派生类对象可以访问基类的public成员,不可以访问基类的protected、private成员。

protected继承:派生类可以访问基类的public、protected成员,不可以访问基类的private成员;
派生类对象不可以访问基类的public、protected、private成员。

private继承:派生类可以访问基类的public、protected成员,不可以访问基类的private成员;
派生类对象不可以访问基类的public、protected、private成员。

在这里插入图片描述

[144]继承是否破坏了封装?是

封装:通过公有化方法访问私有化属性,使得数据不容易被任意窜改,常用private修饰属性;
继承:通过子类继承父类从而获得父类的属性和方法,正常情况下,用protected修饰属性,专门用于给子类继承的,权限一般在本包下和子类里;

继承破坏了封装:是因为属性的访问修饰符被修改,使得属性在本包和子类里可以任意修改属性的数据,数据的安全性从而得不到保障。

[145]vector添加元素

push_back() emplace_back()

emplace_back() 和 push_back() 的区别,就在于底层实现的机制不同,emplace_back() 的执行效率比 push_back() 高。push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。

[146]Vector删除元素

erase,remove,swap

[147]vector容器的三种遍历方法

方法一:採用下标遍历
方法二:採用迭代器遍历
方法三:利用copy函数遍历

copy(b,e,b1),作用是将迭代器范围[b,e)内的元素拷贝到以迭代器b1開始的位置

[148]基于范围的遍历与迭代器遍历区别是什么?

在这里插入图片描述
在这里插入图片描述
for循环便于访问顺序存储的记录,而foreach和迭代器便于访问链接存储
在这里插入图片描述

[149]简述一下移动构造函数,什么库用到了这个函数

C++11中新增了移动构造函数。与拷贝类似,移动也使用一个对象的值设置另一个对象的值。但是,又与拷贝不同的是,移动实现的是对象值真实的转移(源对象到目的对象):源对象将丢失其内容,其内容将被目的对象占有。移动操作的发生的时候,是当移动值的对象是未命名的对象的时候。这里未命名的对象就是那些临时变量,甚至都不会有名称。典型的未命名对象就是函数的返回值或者类型转换的对象。使用临时对象的值初始化另一个对象值,不会要求对对象的复制:因为临时对象不会有其它使用,因而,它的值可以被移动到目的对象。做到这些,就要使用移动构造函数和移动赋值:当使用一个临时变量对对象进行构造初始化的时候,调用移动构造函数。类似的,使用未命名的变量的值赋给一个对象时,调用移动赋值操作。

移动操作的概念对对象管理它们使用的存储空间很有用的,诸如对象使用new和delete分配内存的时候。在这类对象中,拷贝和移动是不同的操作:从A拷贝到B意味着,B分配了新内存,A的整个内容被拷贝到为B分配的新内存上。
而从A移动到B意味着分配给A的内存转移给了B,没有分配新的内存,它仅仅包含简单地拷贝指针。

移动构造是需要通过移动构造函数来完成的。
移动构造函数定义形式:
class_name(class_name && )

在这里插入图片描述

[150]初始化列表语法

在这里插入图片描述

[151]对象成员

在这里插入图片描述

[152] 请你回答一下 C++ 类内可以定义引用数据成员吗?

c++类内可以定义引用成员变量,但要遵循以下三个规则:
1不能用默认构造函数初始化,必须提供有参构造函数来初始化引用成员变量。否则会造成引用未初始化错误。
2构造函数的形参也必须是引用类型。
3不能在构造函数的函数体赋值,必须在初始化列表中进行初始化。
在这里插入图片描述

[153]简述一下什么是常函数,有什么作用

类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员(准确地说是非静态数据成员)作任何改变。在设计类的时候,一个原则就是对于不改变数据成员的成员函数都要在后面加const,而对于改变数据成员的成员函数不能加 const。

所以 const 关键字对成员函数的行为作了更明确的限定:有 const 修饰的成员函数(指 const 放在函数参数表的后面,而不是在函数前面或者参数表内),只能读取数据成员,不能改变数据成员;没有 const 修饰的成员函数,对数据成员则是可读可写的。除此之外,在类的成员函数后面加 const 还有什么好处呢?那就是常量(即 const)对象可以调用 const 成员函数,而不能调用非const修饰的函数。正如非const类型的数据可以给const类型的变量赋值一样,反之则不成立。

  1. 常量对象只能调用常函数,不能调用非常函数

[154]什么是虚继承(菱形继承),解决什么问题,如何实现?

虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝。这将存在两个问题:其一,浪费存储空间;第二,存在二义性问题,通常可以将派生类对象的地址赋值给基类对象,实现的具体方式是,将基类指针指向继承类(继承类有基类的拷贝)中的基类对象的地址,但是多重继承可能存在一个基类的多份拷贝,这就出现了二义性。虚继承可以解决多种继承前面提到的两个问题

C++标准库中的 iostream 类就是⼀个虚继承的实际应⽤案例。 iostream 从 istream 和 ostream 直接继承⽽来,⽽ istream 和 ostream ⼜都继承⾃⼀个共同的名为 baseios 的类,是典型的菱形继承。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
菱形继承中A只有一份,虚继承中,A共享。
上面的虚继承表实际上是一个指针数组。B、C实际上是虚基表指针,指向虚基表。
虚基表:存放相对偏移量,用来找虚基类
在这里插入图片描述
值相同,a的4,b:b的4字节、a的4字节,ab的虚函数指针
D:a,b,c,d,ab的虚函数指针,ac的虚函数指针

[155]如何通过⼿动的⽅式强⾏调⽤虚表中的函数?

在这里插入图片描述

[156]简述一下虚函数和纯虚函数,以及实现原理

C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。如果调用非虚函数,则无论实际对象是什么类型,都执行基类类型所定义的函数。非虚函数总是在编译时根据调用该函数的对象,引用或指针的类型而确定。如果调用虚函数,则直到运行时才能确定调用哪个函数,运行的虚函数是引用所绑定或指针所指向的对象所属类型定义的版本。虚函数必须是基类的非静态成员函数。虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。

虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。

每一个类都有一个虚函数表
当类中有虚函数时,类中会有虚函数表;当实例化类对象时,对象会多出四个字节存个虚函数表指针
虚函数按照其声明顺序放于表中。
在这里插入图片描述

特别清晰
在这里插入图片描述
添加链接描述

添加链接描述

• 虚函数表的内容在编译时候就已经确定;
• 对象在构造前就已经分配好内存,在进入构造函数之前就已经将虚函数表地址给了对象了;
• 进一步的,虚函数表给对象,在初始化列表之前;
• 我们都知道初始化列表先于构造函数函数体实现

C++内部为每一个类维持一个虚函数表,该类的所有对象都指向同一个虚函数表。

父类的虚函数在子类的虚函数前面。

添加链接描述

添加链接描述
在这里插入图片描述

[157]说说纯虚函数能实例化吗,为什么?派生类要实现吗,为什么?

纯虚函数不可以实例化,但是可以用其派生类通过重写该函数实例化
虚函数的原理采用 vtable。类中含有纯虚函数时,其vtable 不完全,有个空位。
即“纯虚函数在类的vftable表中对应的表项被赋值为0。也就是指向一个不存在的函数。由于编译器绝对不允许有调用一个不存在的函数的可能,所以该类不能生成对象。在它的派生类中,除非重写此函数,否则也不能生成对象。”
所以纯虚函数不能实例化。

纯虚函数是在基类中声明的虚函数,它要求任何派生类都要定义自己的实现方法,以实现多态性。定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。
纯虚函数的意义,让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。

纯虚函数一般在基类不实现
纯虚析构函数一定要在类外写实现

[158]说说C++中虚函数与纯虚函数的区别

虚函数和纯虚函数可以定义在同一个类中,含有纯虚函数的类被称为抽象类,而只含有虚函数的类不能被称为抽象类。
虚函数可以被直接使用,也可以被子类重载以后,以多态的形式调用,而纯虚函数必须在子类中实现该函数才可以使用,因为纯虚函数在基类有声明而没有定义。(纯虚析构例外)
虚函数和纯虚函数都可以在子类中被重载,以多态的形式被调用。
虚函数和纯虚函数通常存在于抽象基类之中,被继承的子类重载,目的是提供一个统一的接口。
虚函数的定义形式:virtual{};纯虚函数的定义形式:virtual { } = 0;在虚函数和纯虚函数的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时要求前期绑定,然而虚函数却是动态绑定,而且被两者修饰的函数生命周期也不一样。

[159]虚函数实现原理

(1) 虚函数(Virtual Function)是通过张虚函数表(Virtual Table)来实现
(2)表中存放的是一个类的虚函数的地址表。
(3)C++的编译器应该保证虚函数表的指针存在于对象实例中最前面的位置,这样可以保证最快的取虚函数表效率。

  1. 每个含有virtual函数的class都有⼀个vtbl(虚函数表),vtbl中存储的是指向各个虚函数 的函数指针;
  2. 每个对象内存空间内存在⼀个vptr(虚指针),这个vptr指向类的vtbl
  3. 当对象调⽤某个virtual函数的时候,编译器根据对象的vptr找到类的vtbl,在vtbl中寻找适当的函数指针
    在这里插入图片描述

[160]虚函数的开销问题

空间开销:包含虚函数的类⽣成⼀个虚函数表,致使程序的⼆进制⽂件⼤⼩会相应的增⼤;
类的实例包含⼀个虚函数表指针,致使对象实例空间占⽤增加⼀个指针⼤⼩

时间开销:增加了⼀次内存寻址,通过虚函数表指针找到虚函数表

[续]C++岗位求职面试八股文第九篇

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT与Fintech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值