Day3: 5道C++ 面向对象高频题整理

news/2024/5/28 2:57:33/ 标签: c++, 开发语言

1、虚函数表是针对类的还是针对对象的?同一个类的两个对象的虚函数表是怎么维护的?

答:虚函数表,或者称为vtable,是针对类的。虚函数表是一个存储类中所有虚函数地址的数组。当我们定义一个类,并在其中声明了虚函数时,编译器就会为这个类生成一个虚函数表。

每一个对象(或者说是实例),只要它的类有虚函数,那么它就会有一个指向这个类的虚函数表的指针。这意味着,同一个类的各个对象,它们的虚函数表指针都指向同一个虚函数表。所以,虽然每个对象都有自己的虚函数表指针,但是同一个类的所有对象共享同一个虚函数表。

举个例子,假设我们有一个基类Animal,它有一个虚函数makeSound()。那么,Animal就有一个虚函数表,其中包含了makeSound()的地址。然后我们创建了两个Animal对象,cat和dog。这两个对象都有一个指针指向Animal的虚函数表,即使是两个不同的对象,但是它们的虚函数表是相同的。

然后,如果我们有一个子类Cat继承自Animal,并且重写了makeSound()函数。那么,Cat也会有一个虚函数表,其中makeSound()的地址被替换为Cat类中的makeSound()函数的地址。当我们创建一个Cat对象kitty时,kitty的虚函数表指针就会指向Cat的虚函数表。

2、为什么基类的构造函数不能定义为虚函数?

在C++中,基类的构造函数不能被定义为虚函数,原因有两个:

  • **构造函数的目的是初始化对象。**当我们创建一个对象时,构造函数被调用来初始化对象的数据成员。在这个阶段,对象才刚刚开始被构建,还没有完全形成,因此它还不具备执行虚函数调用的条件(即,动态绑定)。因为执行虚函数调用需要通过对象的虚函数表指针,而这个指针在构造函数执行完毕后才会被设置。
  • **虚函数通常在有继承关系的类中使用,用于实现多态。**在子类对象的构造过程中,首先会调用基类的构造函数,然后才是子类的构造函数。如果基类的构造函数被定义为虚函数,那么在执行基类的构造函数时,由于子类的部分还没有被构造,所以无法正确地执行子类构造函数中对虚函数的重写。这就破坏了虚函数的目的,即允许子类重写基类的行为。

因此,基于以上原因,C++不允许构造函数为虚函数。但是,析构函数可以(并且通常应该)被声明为虚函数,以确保当删除一个指向派生类对象的基类指针时,派生类的析构函数能被正确调用,避免资源泄露。

3、为什么基类的析构函数需要定义为虚函数?

在C++中,基类的析构函数应该被定义为虚函数,主要是为了能正确地释放动态分配的资源,避免内存泄漏。

当我们使用基类指针指向派生类对象,并使用delete删除这个指针时,如果基类的析构函数不是虚函数,那么只有基类的析构函数会被调用。这样,派生类的析构函数就没有机会被调用,导致派生类中的资源没有被正确释放,造成内存泄漏。

而如果我们将基类的析构函数定义为虚函数,那么在删除基类指针时,就会根据这个指针实际指向的对象类型,调用相应的析构函数,先调用派生类的析构函数,然后再调用基类的析构函数。这样就能确保所有的资源都被正确释放,避免内存泄漏。

举个例子,假设我们有一个基类Animal和一个派生类Cat,Cat类在堆上分配了一些资源。如果我们用一个Animal指针指向一个Cat对象,然后用delete删除这个指针,如果Animal的析构函数不是虚函数,那么只有Animal的析构函数会被调用,Cat的析构函数不会被调用,Cat在堆上分配的资源就没有被释放,造成内存泄漏。而如果Animal的析构函数是虚函数,那么就会先调用Cat的析构函数,释放Cat的资源,然后再调用Animal的析构函数,这样就避免了内存泄漏。

4、构造函数和析构函数能抛出异常吗?

在C++中,构造函数和析构函数都可以抛出异常,但这并不是一个被推荐的做法,原因如下:

构造函数抛出异常:

如果在构造函数中抛出异常,那么对象的构造过程就会被中断。这就意味着对象可能处于一个部分初始化的状态,其成员可能没有被正确初始化。如果你试图在后续的代码中使用这个对象,可能会出现未定义的行为。

举个例子,你有一个DatabaseConnection类,其构造函数试图连接到数据库。如果连接失败,构造函数就抛出一个异常。这个时候,如果你在后续的代码中试图使用这个DatabaseConnection对象,就可能出现问题,因为它并没有正确地初始化。

析构函数抛出异常:

如果在析构函数中抛出异常,情况就更复杂了。析构函数通常在对象生命周期结束时被调用,或者在释放动态分配的内存时被调用。如果在这个过程中析构函数抛出了异常,而你又没有正确地捕获这个异常,那么程序就可能会中断,并可能导致资源泄露。

更糟糕的是,如果析构函数是在处理另一个异常时被调用,并在这个过程中又抛出了一个新的异常,那么C++会立即调用std::terminate,程序会立即终止。

因此,虽然构造函数和析构函数都可以抛出异常,但是在大多数情况下,我们应该尽量避免在这两个函数中抛出异常,或者至少确保这些异常被正确地捕获和处理,以避免未定义的行为

5、如何让一个类不能实例化?

在C++中,如果你希望一个类不能被实例化,也就是不能创建该类的对象,你可以通过以下两种方式来实现:

声明类的构造函数为protected或private: 如果一个类的构造函数被声明为protected或private,那么在类的外部就不能直接调用这个构造函数来创建类的对象。只有类本身和它的友元函数或类可以访问它的私有或保护成员。

class NonInstantiable1 {
private:NonInstantiable1() {} // private constructor
};

将类声明为抽象基类(Abstract Base Class, ABC): 如果一个类至少有一个纯虚函数,那么这个类就是抽象基类,无法被实例化。纯虚函数是在基类中声明但不定义的虚函数,它在基类中的声明形式如下:virtual void func() = 0;。纯虚函数使得派生类必须提供自己的实现,否则派生类也将成为抽象基类。

class NonInstantiable2 {
public:virtual void func() = 0; // pure virtual function
};

上述两种方式都可以让一个类不能直接实例化,但是可以作为基类被继承。在派生类中,你可以提供构造函数的实现或者实现基类中的纯虚函数,使得派生类可以被实例化。
 


http://www.ppmy.cn/news/1434638.html

相关文章

软件游戏缺失d3dcompiler_43.dll怎么修复?分享多种靠谱的解决方法

在我们日常频繁地操作和使用电脑的过程中,时常会遇到一些突发的技术问题。其中一种常见的情况是,在尝试启动或运行某个应用程序时,系统会弹出一个错误提示窗口,明确指出当前电脑环境中缺少了一个至关重要的动态链接库文件——d3dc…

【2024官方文档版学习笔记】React-脱围机制

系列文章 一、 React快速入门 二、React描述IU 三、React添加交互 四、React状态管理 五、React脱围机制 五、脱围机制 “脱围机制”(Fallback Mechanism)通常指的是在组件加载过程中,当遇到加载失败或者加载时间过长的情况时,能…

Springboot的日常操作技巧

文章目录 1、自定义横幅2、容器刷新后触发方法自定义3、容器启动后触发方法自定义**CommandLineRunner**ApplicationRunner 不定时增加 参考文章 1、自定义横幅 简单就一点你需要把banner.text放到classpath 路径下 ,默认它会找叫做banner的文件,各种格式…

vue封装请求、合并js、合并多个js

vue封装请求、合并js、合并多个js 作为一个后端开发,写前端时发现,每次导入api接口都会有一堆代码,像下面这样: import {footprintList, footprintDelete} from /api/userApi.js import {addressList} from /api/userApi.js impor…

【软件工程与实践】(第四版)第6章习题答案详解

第6章 一、填空题二、选择题三、简答题四、实践题 一、填空题 (1) 编程语言是人与计算机交流的 工具。 (2) 从语言层次上,编程语言可以分为 低级语言 和 高级语言 两种类型。 (3) 1960年代出现…

设计模式-创建型-抽象工厂模式-Abstract Factory

UML类图 工厂接口类 public interface ProductFactory {Phone phoneProduct();//生产手机Router routerProduct();//生产路由器 } 小米工厂实现类 public class XiaomiFactoryImpl implements ProductFactory {Overridepublic Phone phoneProduct() {return new XiaomiPhone…

聊聊linux的文件缓存

序 本文主要研究一下linux的文件缓存 文件缓存 linux使用page cache来缓存最近读取的文件,也有目录结构(dcache: Directory Entry Cache)缓存及inode缓存,它们都使用了LRU算法来管理这些page及dentries cache vmstat ## vmstat procs -----------me…

【Python打包exe文件】

Python打包exe文件 ■ Python打包exe文件■■■ ■ Python打包exe文件 需求: 自己写的Python代码,在对方电脑里没有安装py环境无法运行,怎么办? 答:打包成exe文件发送对方就能运行。 首先自己写的python代码自己要能…

JetBrains PhpStorm v2024.1 安装教程 (PHP集成开发IDE)

前言 PhpStorm是由JetBrains推出的一款轻量级集成开发环境,专为PHP开发者而设计。该软件融合了智能的HTML/CSS/JavaScript/PHP编辑器、代码质量分析工具、版本控制系统集成(包括SVN和GIT)、调试和测试等功能。除此之外,PhpStorm还…

第二期书生浦语大模型训练营第四次笔记

大模型微调技术 大模型微调是一种通过在预训练模型的基础上,有针对性地微调部分参数以适应特定任务需求的方法。 微调预训练模型的方法 微调所有层:将预训练模型的所有层都参与微调,以适应新的任务。 微调顶层:只微调预训练模型…

基于百度文心大模型全面重构,小度正式推出AI原生操作系统DuerOS X

4月16日,以“创造未来”为主题的2024百度Create AI开发者大会在深圳举办。百度集团副总裁、小度科技CEO李莹正式发布了小度新一代操作系统DuerOS X,该操作系统是小度基于百度文心大模型推出的全球首个AI原生操作系统。李莹表示:“作为⽂⼼⼤模…

IDEA中添加servlet模板

官方代码链接 #if (${PACKAGE_NAME} && ${PACKAGE_NAME} ! "")package ${PACKAGE_NAME};#end #parse("File Header.java")import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException…

C++:类与对象完结篇

hello,各位小伙伴,本篇文章跟大家一起学习《C:运算符重载》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 ! 文章目录 重新认识构造函数1.初始化列表2.explicit关键字 static成员1.sta…

Elasticsearch进阶篇(三):ik分词器的使用与项目应用

ik分词器的使用 一、下载并安装1.1 已有作者编译后的包文件1.2 只有源代码的版本1.3 安装ik分词插件 二、ik分词器的模式2.1 ik_smart演示2.2 ik_max_word演示2.3 standard演示 三、ik分词器在项目中的使用四、ik配置文件4.1 配置文件的说明4.2 自定义词库 五、参考链接 一、下…

轻量级SQLite可视化工具Sqliteviz

什么是 Sqliteviz ? Sqliteviz 是一个单页面离线优先的渐进式网络应用(PWA),用于完全客户端的 SQLite 数据库或 CSV 文件的可视化。 所谓完全客户端,就是您的数据库永远不会离开您的计算机。使用 sqliteviz&#xff0c…

11、【桥接模式】让将抽象和实现分离,使得它们可以独立地变化

你好,我是程序员雪球。 今天我们来聊聊 23 种设计模式中,一种常见的结构型模式,桥接模式。聊聊它的设计思想、应用场景,以及如何使用。 一、设计思想 桥接模式(Bridge Pattern)是一种结构型设计模式&#…

拿捏 顺序表(1)

目录 1. 顺序表的分类2. 顺序表实现3. 顺序表实现完整代码4. 总结 前言: 一天xxx想存储一组数据, 并且能够轻松的实现删除和增加, 此时数组大胆站出, 但是每次都需要遍历一遍数组, 来确定已经存储的元素个数, 太麻烦了, 于是迎来了顺序表不屑的调侃: 数组你不行啊… 顺序表是一…

mac qt android开发环境

1,安装Android Studio 下载 Android Studio 和应用工具 - Android 开发者 | Android Developers (google.cn)

求建筑高度(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;float x, y;//提示用户&#xff1b;printf("请输入x y坐标的值&#xff1a;");//…

HarmonyOS NEXT星河版之实战商城App瀑布流(含加载更多)

文章目录 一、目标二、开撸2.1 声明商品对象2.2 mock数据2.3 主页面2.4 加载更多2.5 完整代码 三、小结 一、目标 二、开撸 2.1 声明商品对象 export interface GoodsItem {title: stringimageUrl: string }2.2 mock数据 export const mockGoodsList: GoodsItem[] [{title:…