IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++中经典面试问题(三大特征、隐藏、重载、覆盖,虚函数,异常,智能指针以及强制类型转等) -> 正文阅读

[C++知识库]C++中经典面试问题(三大特征、隐藏、重载、覆盖,虚函数,异常,智能指针以及强制类型转等)

C++(面向对象)的三大特征:

1.封装:将客观事物抽象成类,每个类对自身的数据和方法实行protected(保护),public(公有),private(私有)。

2.继承:广义的继承有三种方式。实现继承、可视继承、接口继承

? ? ? ? ? ? ?实现继承:使用基类的属性和方法而无需额外编码的能力

? ? ? ? ? ? ?可视继承:子窗体使用父窗体的外观和实现代码

? ? ? ? ? ? ?接口继承:仅使用属性和方法实现之后到子类实现 ,虚函数继承,为了重写,达成多态

3.多态为了完成某个行为,当不同的对象去完成时会产生不同的状态。是在不同继承关系的类对象中调用同一函数,产生了不同的行为。

构成多态的条件:(1)必须通过基类的指针或者引用调用虚函数

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(2)被调用的函数必须是虚函数,且派生类必须对类型的虚函数重写

4.继承中需要注意的问题:

(1).基类(父类)中private成员被继承到了子类中,但无论在类内类外都不能访问它

(2).基类成员不想在类外被访问,需要在派生类中访问,就定义为protected,保护成员。

(3).基类的私有成员在子类中都不可见。

(4).使用关键字class时默认继承方式private,struct默认方式是public。

(5).实际应用中一般都是public。

(6).派生类对象可赋值给基类的对象/指针/引用。

(7).基类对象不能给派生类对象赋值.

(8).基类的指针可通过强制类型转换赋值给派生类的指针。(但必须基类指针指向派生类对象才安全)。

5.继承中的作用域问题:

(1)基类和派生类都有独立的作用域

(2)子类和父类中有同名函数,子类屏蔽父类对同名函数的访问,叫隐藏,也叫重定义。(可使用基类::基类成员 显示访问),

(3)若对成员函数隐藏,只需函数名相同。

(4)最好不定义同名函数

经典面试题:实现一个不能被继承的类。

// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:
    static NonInherit GetInstance()
    {
        return NonInherit();
    }
private:
    NonInherit()
    {}
};
 
// C++11给出了新的关键字final禁止继承
class NonInherit final
{};

6.友元:友元关系不能继承。

7.什么是菱形继承?菱形继承的问题是什么?

? ? ? ? ?复杂继承分为单继承,多继承,菱形继承是多继承的一种特殊形式,就是定义一个类,分别用2个派生类去继承父类,再定义一个类继承这两个派生类。菱形继承具有数据冗余和二义性的问题。

8.派生类构造对象的构造与析构过程

派生类构造,拷贝构造,运算符重载对象时必须调用基类,并初始化基类的成员。析构函数自动调用基类析构函数。派生类对象初始化先调用基类在调用派生类构造,派生类对象析构先调用派生类在调用基类。

9.虚函数:被virtual修饰的类成员函数称为虚函数。

10.虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(返回值,函数名字,参数列表完全相同)。称子类虚函数重写了基类虚函数。

11.重载,隐藏,重写(覆盖)的区别:

(1)重载是在类内进行的,同名不同参。作用域相同。参数列表必须不同。

(2)隐藏是继承父子类中函数名相同,子类屏蔽父类的同名访问。作用域独立。

(3)重写(覆盖)是同名同参必须相同,是继承父子类中关于虚函数问题。作用域独立。

12.虚函数重写的2个列外:

(1)协变(基类与派生类虚函数返回值类型不同)

(2)析构函数的重写(基类与派生类析构函数名字不同)无论加不加vritual,编译器进行了统一处理。

C++11中,final:修饰虚函数,表示该虚函数不能再被继承。override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。

13.纯虚函数:虚函数后=0为纯虚函数,包含纯虚函数的类叫抽象类(接口类),不能实例化对象。只有重写才能实例化出对象。抽象类强制重写了虚函数,另外抽象类体现出了接口继承关系。

14.虚函数表:一个含有虚函数的类中都至少都有一个虚函数表指针_vfptr,简称虚表。虚表存的是虚函数指针。虚函数是在编译阶段就生成的,一般情况下存在代码段(常量区)的。

15.静态多态(绑定)与动态多态(绑定)

静态多态:在程序编译期间确定了程序的行为。又称前期绑定。例如:函数重载。

动态多态:是在程序运行期间,根据具体拿到的类型确定程序的具体行为,调用具体的函数。

16. inline函数可以是虚函数吗?

答:不能,因为inline函数没有地址,无法把地址放到虚函数表中。
17. 静态成员可以是虚函数吗?

答:不能,因为静态成员函数没有this指针,使用类型::成员函数的调用方式
无法访问虚函数表,所以静态成员函数无法放进虚函数表。
18. 构造函数可以是虚函数吗?

答:不能,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。
19. 析构函数可以是虚函数吗?什么场景下析构函数是虚函数?

答:可以,并且最好把基类的析构函数定义成虚函数。
20. 对象访问普通函数快还是虚函数更快?

答:首先如果是普通对象,是一样快的。如果是指针对象或者是引用对象,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。

/*************************************************************************************************************/
21.C++中的异常:抛出异常,让函数直接或间接的调用者处理。

throw:程序抛出异常,通过throw关键字处理。

catch:捕获异常,可多个catch捕获。

try:特定异常,后跟一个或多个catch块。

22.异常的抛出与匹配原则:

(1)异常是抛出对象而引发的,对象的类型决定了用哪个catch块处理。

(2)被选中的处理代码是与该类型匹配离抛出异常位置最近的一个。

(3)抛出异常后,会生成一个异常对象的拷贝,会在catch以后销毁。

(4)catch可以捕获任意类型异常。

(5)可以抛出的派生类对象,使用基类捕获,这个在实际中非常实用(在大型项目中,统一)

23.在函数调用链中异常栈展开匹配原则:

(1)检查throw本身是否在try块内部,如果是再查找匹配的catch语句。

(2)?没有匹配的catch则退出当前函数栈,继续在调用函数的栈中进行查找匹配的catch。

(3)?如果到达main函数的栈,依旧没有匹配的,则终止程序.

? ? ? ? ? ? ?(1)(2)(3)称为栈展开。

24.异常安全

(1)最好不要在构造函数中抛出异常,否则可能导致对象不完整或没有完全初始化.

(2)最好不要在析构函数内抛出异常,否则可能导致资源泄漏(内存泄漏、句柄未关闭等)

(3)使用RAII解决(1)(2)问题,解决内存泄露,死锁等问题。

25.异常规范

(1)可在函数的后面接throw(类型),列出这个函数可能抛掷的所有异常类型。
(2)函数的后面接throw(),表示函数不抛异常。
(3)若无异常接口声明,则此函数可以抛掷任何类型的异常。?

异常的优点:更好的定位程序BUG,缺点:会造成内存泄漏,死锁等。

26.RAll(解决异常安全的问题--内存泄漏,死锁等)

RAII是:利用对象生命周期控制程序资源。在对象构造时获取资源,析构时释放资源。

实际上把管理一份资源的责任托管给了一个对象。更好的理解是:给开辟出来的空间找了一个标记,一直到释放为止。

优点:(1)不用显式释放资源 (2)对象所需资源在其生命周期内一直有效。

27.智能指针--std::auto ptr

智能指针实现原理:管理权转移思想。拷贝构造之后,之前的对象空了,通过之前的对象访问资源会出现问题。

C++98中:auto ptr需要重载*和->,才可以解引用和指向空间内容。

C++11中:std::unique_ptr--实现原理:简单粗暴的防拷贝

28.std::shared_ptr:通过引用计数支持智能指针对象的拷贝。实现多个shared_ptr对象之间共享资源。

(1)shared_ptr在其内部,给每个资源都维护了一份计数,用来记录该份资源被几个对象共享。
(2)在对象被销毁时,就说明自己不使用该资源了,对象的引用计数减一。
(3)如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
(4)如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。

std::shared_ptr的线程安全问题:

(1)智能指针对象中引用计数是多个智能指针对象共享的,两个线程中智能指针的引用计数同时++或--,非原子操作,引用计数原来是1,++了两次,可能还是2.这样引用计数就错乱了。会导致资源未释放或者程序崩溃的问题。所以智能指针中引用计数++、--是需要加锁的,也就是说引用计数的操作是线程安全的。
(2)智能指针管理的对象存放在堆上,两个线程中同时去访问,会导致线程安全问题。

/******************************************************************************************************/

29.C++的类型转换

(1)static_cast:静态转换,非多态类型,不能用于两个不相关的类型转换。

(2)reinterpret_cast:通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型

(3)const_cast:最常用的用途就是删除变量的const属性,方便赋值

(4)dynamic_cast:用于将一个父类对象的指针转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针->父类指针/引用(不需要转换,赋值兼容规则)

向下转型:父类对象指针->子类指针/引用(用dynamic_cast转型是安全的)?
注意: 1. dynamic_cast只能用于
含有虚函数的类

? ? ? ? ? ? 2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0

30.explicit:关键字阻止经过转换构造函数进行的隐式转换的发生

31.RTTl:运行时类型识别

? ? ? ? ? C++通过以下方式来支持RTTI:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??1. typeid运算符
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2. dynamic_cast运算符

使用场景:想使用基类对象的指针或引用执行某个派生类操作,并且该操作不是虚函数。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:03:37  更:2021-08-09 10:05:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 19:01:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码