C++面经

 

学习视频参考


1 面向对象的三大特征

1.1 封装

1.1.1 目的

隐藏实现细节,实现模块化。

1.1.2 特性

访问权限:

  • public:可以给所有对象访问。
  • protected:仅对子类开放。
  • private:仅对自己开放,可以通过友元进行访问。

能够对属性和方法进行限定。

1.2 继承

1.2.1 目的

在不修改原有类的情况下,通过继承实现功能的扩展。

1.2.2 特性

解决基类成员在子类中的最高权限

  • public:基类中的属性和方法原来是什么权限,在子类就还是什么权限。
  • protected:基类中的public权限在子类中会变成protected权限。
  • private:基类中的public和protected权限会变成private权限。解决基类成员在子类中的最高权限

注意基类的private权限在子类中存在但不能访问。

子类可以通过using修改基类在子类中的权限,这样就可以访问基类中private权限下的属性和方法。

多继承,C++可以继承多个父类。

 接口继承,存虚函数。

1.3 多态

1.3.1 目的

一个接口多种形态,通过实现接口重用,增强可扩展性。

1.3.2 特性

静态多态

  • 指编译器的多态。
  • 函数重载:同样的函数名不同的参数。

动态多态

  • 指运行时的多态。
  • 通过虚函数重写的方式实现。
  • 基类中有虚函数,子类通过重写基类的虚函数来实现多态。
  • 基类* p = new 子类;通过这种方式实现多态。

2 多态的实现原理

2.1 静态多态

2.1.1 函数重载

  • 允许同一作用域中声明多个功能类似的同名函数。
  • 其参数列表,参数个数,参数类型,参数顺序有所不同。
  • 不能通过返回值类型来区别函数重载。

2.1.2 原理

编译过程中

  • 预编译:把头文件中的函数声明拷贝到源文件当中去。避免编译过程中的语法分析找不到函数定义
  • 编译:语法分析,同时进行符号汇总。
  • 汇编:生成函数名和函数地址之间的映射。方便之后通过函数名找到函数定义位置,从而执行函数。
  • 链接:将多个文件中的符号表汇总合并。

通过函数名修饰达成函数重载的目的。

函数名修饰:在符号汇总中,相同函数名在符号表中的符号是不同的一般是函数名+有规则的前后缀。所以是编译器的多态。

2.2 动态多态

2.2.1 虚函数重写

虚函数重写,运行时确定。

  • 在基类的函数前+virtual关键字,在基类中重写该函数。
  • 运行时会根据对象的类型来调用相应的函数。
  • 如果对象的类型是基类,就调用基类的函数。
  • 如果对象的类型是子类,就调用子类的函数。

2.2.2 原理

  • 早绑定:编译器编译时已经确定了调用对象的函数地址。
  • 晚绑定:使用virtual函数,为类生成虚函数表—一个一维数组,存放了虚函数地址。类对象构造时会初始化该虚函数表指针。其中,虚函数表指针放在类的最前面的8个字节,指向虚函数表,虚函数表中存放类的虚函数地址。

3 菱形继承

3.1 什么是菱形继承

  • 前提:C++具备其他语言所没有的多重继承特性。
  • 原因:一个子类可以继承多个父类,而这些父类可能继承至相同的父类,这样就会造成菱形继承。

3.2 菱形继承有什么样的问题

一个类C,继承B1,B2,而B1,B2又继承至同一个类A。

那么构造类C的时候,我们的B1,B2是分别构造了自己的类A还是构造了不同的类A。也就是C的背后是有一个A还是有两个A?

一般情况下是构造了两个类A 这样就出现了如下的问题:

  • 造成存储空间的浪费。
  • 二义性。

3.3 解决方案

虚继承:

  • 目的:使得子类C只继承一次A。
  • 方法:继承的时候带上virtual关键字。
  • 原理:通过虚表偏移来实现虚继承。父类的虚指针都有到共同基类的偏移量,从而让子类多继承时能指向同一个  父类的父类。

感觉这个菱形继承一般不会有什么人用吧,毕竟其他语言也没有多继承这种东西。


4 override和final

C++11中引入这两个关键字

4.1 引入原因

  • 虚函数复写:1、不能阻止某个虚函数的进一步复写。2、本意是写一个新函数,结果复写了基类的虚函数。3、本意是重写虚函数,但是由于签名不一样导致子类中重新构建了一个虚函数。
  • 类继承:不能阻止某个类的进一步派生。

4.2 override

  • 指定子类的一个虚函数复写基类的一个虚函数。
  • 保证该重写的虚函数与基类的虚函数具体相同的签名。

解决虚函数复写中的3号问题。

4.3 final

  • 指定某个类不能被派生。
  • 指定某个虚函数不能再派生类中被覆写。

解决其他问题。


5 类型推导用法

5.1 类型:

  • 模板参数类型的推导。
  • auto。
  • decltype。

5.2 为什么要引入类型推导

  • C++是强类型语言。
  • 编译器来处理类型推导。
  • 提升语言的编码效率。

5.3 auto

5.3.1 原理:

  • 用于推导变量的类型,通过强制声明一个变量的初始值,编译器会通过初始值进行推导类型。

5.3.2 规则:

  • auto变量必须在定义时进行初始化。

  • 如果用auto定义多个变量,那么这些变量必须是同一类型。
  • 类型推导时会丢失引用&或者丢失const和volitte语义。
  • 保留引用或者cv语义,用auto &。
  • 万能引用使用auto &&。根据初始值的属性来判断是左值引用还是右值引用。
  • auto不能推导数组类型,推导的是数组头部指针。
  • C++14中auto可以推导函数的返回类型。

5.3.3 应用:

  • 尽量使用auto声明变量,除非影响可读性。
  • 使用容器时,迭代器很长。
  • 匿名函数返回值。
  • 模板函数中使用auto,节约模板参数类型。

5.4 decltype

5.4.1 原理

  • decltype用于推导表达式的类型,只分析表达式而不参与运算。

5.4.2 规则

  • exp是一个普通的表达式,推导表达式类型。
  • exp是函数调用,推导函数返回值类型。
  • exp是一个左值,推导左值引用。

5.4.3 应用

  • 泛型编程

6 function,lambda和bind

  • function:类模板。
  • lambda:表达式。
  • bind:函数适配器。

6.1 function

C++11以前,保存函数地址用的是和C语言一样的方式—函数指针。于是C++11就引入了std::function类模板。

6.1.1 function是什么

  • function是一个抽象了函数参数以及函数返回值的一个类模板。

6.1.2 function原理

  • function把任意函数包装成一个对象,该对象可以保存,传递以及复制。
  • 动态绑定,只需修改改对象(赋值不同的function对象),实现类似多态的效果。

6.1.3 function用途

  • 保存普通函数,类的静态成员函数。
  • 保存仿函数(函数对象)。
  • 保存类的成员函数。
  • 保存lambda表达式。
  • 保存bind返回的函数对象。

6.2 仿函数(函数对象)

6.2.1 仿函数是什么

  • 重载了operator()的类。

6.2.2 仿函数的特征

  • 可以有状态(成员变量存储状态)。
  • 有状态的函数称之为闭包。

6.3 lambda表达式

6.3.1 lambda表达式是什么

  • 一种方便创建匿名函数对象的语法糖。

6.3.2 lambda的构成

  • []:捕获列表。捕获外部变量转为类的成员变量。
  • 值捕获:访问匿名函数的外部变量,默认只读,不能修改,使用mutable可以可读可写,这样就不会修改外部变量的值。
  • 引用捕获:可读可写,会修改外部变量的值。
  • ():参数列表。
  • ->:指定返回值。可省略,有类型推导。
  • {}:函数的具体实现。

6.3.3 lambda原理

  • 将lambda表达式转变为一个函数对象。
  • 将lambda的参数列表重载operator(),类似仿函数。

6.4 bind函数适配器

6.4.1 bind函数适配器是什么

  • 用来通过绑定函数以及函数参数的方式生成函数对象的模板函数。
  • 提供占位符,实现灵活的参数绑定。

6.4.2 bind函数适配器的特征

  • 绑定函数以及函数参数,从而构成一个函数对象
  • 允许修改参数顺序

  • 函数对象是一个闭包
  • function是用来描述函数对象的类型。
  • lambda是生成一个能访问外部变量的函数对象。
  • bind是生成一个能够和参数函数对象。

7 继承下的构造函数和析构函数的执行顺序

  • 构造:按照依赖链,越强越先。
  • 析构:按照依赖链,越弱越先。

单继承中:

  • 成员类按顺序构造,按相反顺序析构。
  • 类的构造依赖成员类的构造。
  • 基类比成员类依赖性更强。

多继承中:

  • 成员类按顺序构造,按相反顺序析构。
  • 类的构造依赖成员类的构造。
  • 基类比成员类依赖性更强。
  • 基类按照声明顺序构造,按相反顺序析构。

8 虚函数表和虚函数表指针的创建时机

先产生虚函数表,每个对象都有虚函数表指针。

8.1 虚函数表的创建时机

  • 编译器发现类中包含virtual关键字修饰的函数。
  • 虚函数表的内容在编译器编译的时候就已经生成了。
  • 虚函数表存放在全局数据区中的只读数据段中。
  • 虚函数表是存放虚函数地址的数组。

8.2 虚函数表指针的创建时机

  • 对象构造的时候,在构造函数,将虚函数表的地址赋值给对象的虚函数指针。
  • 如果类没有构造函数,编译器会为该类自动生成一个默认构造函数,从而为类对象初始化虚函数指针。

继承下,虚函数表指针赋值过程:

  • 调用基类构造函数时,先将基类的虚函数表指针地址赋值给vptr。
  • 接着调用子类的构造函数时,将子类的虚函数表地址赋值给vptr。也就是覆盖上面一步的vptr。

9 虚析构函数

  • 作用:在继承下,为了使子类析构函数能够得到正常调用,需要将基类的析构函数设置为虚析构函数。
  • 场景:子类对象指针赋值给基类指针,在调用析构函数时,子类的析构函数不会被调用。
  • 在C++看来,设计某个类的时候,不一定是基类
  • 如果是基类,我们应该手动的将基类的析构函数设置为虚函数。

10 智能指针种类以及使用场景

10.1 指针管理的困境

  • 资源释放了,指针没有置空。野指针:只有一个指针指向资源。指针悬挂:多个指针指向同一个资源。踩内存。
  • 资源忘记释放了。
  • 重复释放资源。

10.2 解决

智能指针采用RAII思想来自动化管理指针所指向的动态资源的释放。

RAII主要利用了对象的生命周期来控制程序资源。

智能指针利用类的构造函数和析构函数来管理资源。

10.3 智能指针的种类

10.3.1 shared_ptr

解决指针悬挂问题。

  • 语义:共享所有权。资源没有明确的拥有者。
  • 原理:引用技术。
  • 场景:容器中管理指针。资源通过函数传递。
  • 使用规范:不要使用原来的裸指针—构造智能指针时,不要暴露裸指针。尽量使用make_shared来构造智能指针。不要通过get来操作裸指针。不要用一个指针构造多个智能指针对象。不要用类对象this作为shared_ptr返回。

10.3.2 weak_ptr

  • 辅助shared_ptr,解决shared_ptr出现的循环引用的问题。
  • 原因是弱引用不占用强引用计数。

10.3.3 unique_ptr

解决指针悬挂问题。

  • 语义:独享所有权。没有赋值运算操作符。仅提供移动构造和移动赋值。
  • 明确某个对象只有一个拥有者。
  • 场景:
  • 使用规范:不支持拷贝,但是可以从函数中返回一个unique_ptr,编译器优化可以解决。make_unique C++14提供的。

 

 

 

相关推荐

  1. C++

    2024-02-17 08:58:01       35 阅读
  2. c++

    2024-02-17 08:58:01       19 阅读
  3. C语言

    2024-02-17 08:58:01       10 阅读
  4. C++

    2024-02-17 08:58:01       4 阅读
  5. 虎牙C++技术

    2024-02-17 08:58:01       31 阅读
  6. Unity(自整)——C#基础

    2024-02-17 08:58:01       16 阅读
  7. C++ 每日一问(一)

    2024-02-17 08:58:01       13 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-17 08:58:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-17 08:58:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-17 08:58:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-17 08:58:01       20 阅读

热门阅读

  1. 【微服安全】API密钥和令牌与微服务安全的关系

    2024-02-17 08:58:01       34 阅读
  2. 【无标题】

    2024-02-17 08:58:01       28 阅读
  3. 算法训练营day29, 贪心算法3

    2024-02-17 08:58:01       32 阅读
  4. transformer的原理

    2024-02-17 08:58:01       30 阅读
  5. Python循环语句——continue和break

    2024-02-17 08:58:01       26 阅读