C++面试速通宝典——20

355. C++生成子类需要虚析构么?

‌‌‌‌  是的。如果你的C++类设计为基类,并且你打算通过基类指针来删除派生类的对象,那么你应该为基类提供一个虚析构函数。这样做可以确保在删除基类指针时,派生类的析构函数会被正确调用,从而避免资源泄露或其他析构相关的问题。

356. C++虚函数底层是如何实现的?

‌‌‌‌  C++中虚函数的底层实现通常是通过虚函数表(虚表,vtable)实现的。每个包含虚函数的类都有一个虚表,此表是一个包含指向类的虚函数的函数指针的数组。每个对象都包含了一个指针(虚指针,vptr),指向基类的虚表。当调用虚函数时,实际上是通过对象的虚指针查找虚表,然后通过虚表调用对应的函数实现的,这允许在运行时进行多态行为。

357. 虚表是存放在哪里的?

‌‌‌‌  虚表(vtable)通常存放在程序的只读数据段(.rodata section)中,这是因为虚表包含的函数地址不会在运行时改变。每个对象的虚指针(vptr)指向基类的虚表,确保正确调用对应类的虚函数。

358. 什么是结构体对齐?结构体对齐的规则?怎么判断结构体大小?

‌‌‌‌  结构体对齐是指在结构体中,每个成员的起始地址相对于结构体起始地址的偏移量是该成员大小的整数倍,这样做是为了满足某些平台对数据存储对齐的要求,提高内存的访问效率。

结构体对齐规则通常遵循以下原则:

  1. 结构体的起始地址能够被其最宽基本类型成员的大小所整除
  2. 结构体每个成员相对于结构体起始地址的偏移量应是该成员大小的整数倍,不是的话会进行填充
  3. 结构体的总大小为其最宽基本类型成员大小的整数倍

判断结构体大小的方法:

  1. 确定每个成员的大小和对齐要求。
  2. 根据成员声明顺序,为每个成员分配地址空间,必要时进行填充。
  3. 按最大成员对齐要求在结构体末尾可能添加填充。
  4. 结构体总大小就是最后一个成员末尾地址加上末尾填充(如果有的话)。

使用sizeof(结构体类型名)表达式可以直接得到结构体的大小。

解释

‌‌‌‌  这里不知道你有没有疑问,我开始的时候有个疑问:“结构体每个成员相对于结构体起始地址的偏移量应是该成员大小的整数倍,不是的话会进行填充”这句话,不应该是最宽基本类型成员大小的整数倍吗?

‌‌‌‌  然后我试了一下,发现不是这样的。

解释

每个成员的对齐要求是基于它自身的大小。例如:

  • char 通常对齐到 1 字节。
  • int 通常对齐到 4 字节。
  • double 通常对齐到 8 字节。

对齐要求是指每个成员的起始地址必须是它对齐大小的整数倍。

示例

考虑下面的结构体:

struct Example {char a;    // 对齐要求是 1 字节int b;     // 对齐要求是 4 字节char c;    // 对齐要求是 1 字节
};
计算偏移量和填充
  1. char a:

    • 大小:1 字节
    • 对齐要求:1 字节
    • 偏移量:0
    • 不需要填充
  2. int b:

    • 大小:4 字节
    • 对齐要求:4 字节
    • 当前偏移量:1(因为 char a 占据了 1 字节)
    • 为了满足 int 的 4 字节对齐要求,需要在 char a 后添加 3 个填充字节
    • 新的偏移量:4
    • int b 放置在偏移量 4
  3. char c:

    • 大小:1 字节
    • 对齐要求:1 字节
    • 当前偏移量:8(因为 int b 占据了 4 字节)
    • char c 放置在偏移量 8
总大小

‌‌‌‌  为了满足结构体对齐规则,结构体的总大小需要是其最宽基本类型成员大小(即 int 的 4 字节)的整数倍。当前结构体的大小是 9 字节(1 字节 char a + 3 字节填充 + 4 字节 int b + 1 字节 char c)。需要再添加 3 个填充字节使总大小成为 12 字节。

总结

  • 每个成员相对于结构体起始地址的偏移量应是该成员对齐要求的整数倍,这与结构体中最宽基本类型成员的大小无关。
  • 如果当前偏移量不满足该成员的对齐要求,就需要添加填充字节。
  • 结构体的总大小需要是结构体中最宽基本类型成员的大小的整数倍
struct Example {char a;    // 偏移量 0// 3 字节填充int b;     // 偏移量 4char c;    // 偏移量 8// 3 字节填充
};

最终总大小:12字节

359. 线程间怎么同步?同步是解决什么问题?

主要的目的是为了防止多个线程同时操作同一片内存空间,导致数据的不一致。

线程间的同步可以通过多种机制实现,包括但不限于以下几种:

  1. 互斥锁(Mutex):当一个线程使用互斥锁保护的资源时,其他需要这些资源的线程将被阻塞,直到该线程释放资源。
  2. 信号量(Semaphore):他是一个计数器,用来保护一个或者多个相同的资源。当没有可用资源时,需要这些资源的线程将被阻塞。
  3. 条件变量(Condition Variables):它可以用来让一个线程等待某个条件成立,而不是忙等。
  4. Event/Message Queue:线程通过发送和接收事件或消息进行通信。接收线程将被阻塞,直到有事件或消息可接收。

360. 如何避免死锁?死锁的条件是什么?

避免死锁的一些常见策略包括:

  1. 破坏互斥条件:尽可能减少对资源的互斥访问。
  2. 破环请求并等待条件:一次性申请所有资源,而不是分步申请。
  3. 破坏不可剥夺条件:使资源可以被抢占,当某个线程需要资源时,已经分配的资源可以被回收。
  4. 破坏循环等待条件:对资源请求进行排序,按照一定顺序获取资源。

死锁发生的条件有四个,通常被称为死锁的必要条件:

  1. 互斥:资源不能被共享,只能由一个线程同时使用。

  2. 持有和等待:线程已经持有至少一个资源,但又提出了新的资源请求,而该资源被其他线程持有。

  3. 不可抢占:线程持有的资源在未完成其任务前,不能被其他线程抢占。

  4. 循环等待:存在一种线程资源的循环等待关系。

361. vector底层是什么数据结构?

‌‌‌‌  vector底层是使用连续内存空间来实现的动态数组。

362. vector空间不够了底层会怎么做?

‌‌‌‌  当vector空间不够时,他的底层实现会分配一个更大的连续内存块将现有的元素复制到新的内存块中然后释放原来的内存块,并更新内部状态以反映新的容量。

363. vector resize是怎么做的?

vector的resize操作主要完成以下步骤:

  1. 判断新的大小是否大于当前的容量,如果是,则需要额外分配内存空间
  2. 如果新的大小比当前元素数量少,将会销毁多余的元素
  3. 如果新的大小比当前元素数量多,将会在容器尾部创建新的元素
  4. 更新内部的元素数量为新的大小

364. C++里面的成员函数和普通函数有什么区别?

主要区别如下:

  1. 成员函数是类的组成部分,他们可以访问类的私有、保护和公共成员。而普通函数不是类的一部分,不可以直接访问类的私有和保护成员
  2. 成员函数在调用时需要使用对象或者指向对象的指针或引用来调用,而普通函数则不需要
  3. 成员函数可以被声明为虚函数,形成多态性。而普通函数不能
  4. 成员函数可以被重载,但是不能被重定义。

365. C++成员函数是怎么访问到成员变量的?

‌‌‌‌  C++中,成员函数可以直接访问属于相同类的成员变量,因为他们在调用时隐含的接收一个指向调用对象的指针(通常命名为this)。this指针提供了对调用对象成员变量的直接访问方式。

解释:

成员函数和普通函数的重载和重定义

重载(Overloading)

重载指的是在同一个作用域内,函数名相同但参数列表不同的多个函数。重载函数可以具有不同的参数类型或数量,返回类型可以相同或不同。重载主要通过参数列表来区分不同的函数。

  • 成员函数重载:
class MyClass {
public:void func(int a) {}void func(double a) {}
};

普通函数重载:

void func(int a) {}
void func(double a) {}
重定义(Redefinition)

重定义通常指的是在同一个作用域内定义两个完全相同的函数,包括函数名、参数列表和返回类型。C++ 中不允许这种情况。

例如,以下代码会导致编译错误:

void func(int a) {}
void func(int a) {}  // 错误,函数重定义

成员函数与普通函数的重定义和重载

  • 成员函数可以被重载,但不能被重定义。
  • 普通函数可以被重载,但不能被重定义。

这两点的含义如下:

  • 重载:无论是成员函数还是普通函数,都可以重载,即在同一个作用域内定义多个具有相同名称但参数列表不同的函数。

  • 重定义:无论是成员函数还是普通函数,都不能重定义,即不能在同一个作用域内定义两个完全相同的函数。

特别注意

需要注意的是,成员函数的重定义与普通函数的重定义在继承和作用域中有不同的处理方式:

  • 成员函数重定义: 在继承关系中,派生类可以重定义基类的成员函数。这个过程叫做函数覆盖(overriding),它与函数重定义的概念不同。在覆盖中,派生类重新定义了基类的虚函数。
class Base {
public:virtual void func() {}
};class Derived : public Base {
public:void func() override {}  // 覆盖基类的虚函数
};
  • 普通函数重定义: 普通函数没有类似成员函数覆盖的机制。在同一作用域内定义两个完全相同的普通函数会导致编译错误。

总结:

  • 成员函数和普通函数都可以被重载。
  • 在同一作用域内,成员函数和普通函数都不能被重定义。
  • 在继承关系中,派生类可以覆盖基类的虚函数。

366. unity脚本如何与引擎绑定的?

在Unity中,脚本与具体的游戏对象(引擎实体)绑定的方式一般如下:

  1. 首先,创建一个脚本。这可以通过Unity编辑器的“Assets”菜单,选择“Create”-> “C# Script”
  2. 接着,将这个脚本拖放到游戏对象上,或者在游戏对象被选中的情况下,直接在检查器窗口点击“Add Component”,然后选择你的脚本。

‌‌‌‌  这样,你的脚本就与指定的游戏对象绑定了。然后脚本内的函数就可以通过this.gameObject来访问和控制绑定的游戏对象。

367. 讲一下 noexcept如果出现了异常会怎么办?

‌‌‌‌  如果在声明为noexcept的函数中出现了异常,程序会调用 std::terminate()来立即终止程序执行。

解释

在C++中,noexcept是一个关键字,用于指示一个函数不会抛出任何异常。其主要作用是帮助编译器优化代码,并且在某些情况下可以提高程序的性能和稳定性。你提到的std::terminate是C++标准库中的一个函数,用于在程序遇到无法处理的异常或其他致命错误时立即终止程序的执行。

详细解释

1. noexcept关键字

当你声明一个函数为noexcept时,你告诉编译器和程序的使用者,这个函数在任何情况下都不会抛出异常。例如:

void myFunction() noexcept {// Function implementation
}
2. 异常安全性检查

‌‌‌‌  如果一个函数被声明为noexcept,但在函数体内抛出了异常,程序的行为将会非常明确——它会立即调用std::terminate函数来终止程序。这是因为抛出异常的行为与noexcept的承诺相违背。

3. std::terminate函数

std::terminate是C++标准库中的一个函数。当程序遇到以下情况之一时,会调用std::terminate

  • 一个未捕获的异常到达了程序的顶层(即,没有任何catch块可以处理它)。
  • 一个构造函数或析构函数在处理异常时抛出了另一个异常。
  • 在一个noexcept函数中抛出了异常。

默认情况下,std::terminate会调用std::abort,导致程序立即终止,不会进行任何清理操作,也不会调用任何析构函数或atexit注册的函数。

示例

以下是一个简单示例,展示了在noexcept函数中抛出异常时会发生什么:

#include <iostream>
#include <stdexcept>void myFunction() noexcept {throw std::runtime_error("Exception in noexcept function");
}int main() {try {myFunction();} catch (const std::exception& e) {std::cout << "Caught exception: " << e.what() << std::endl;}std::cout << "This line will not be executed." << std::endl;return 0;
}

‌‌‌‌  在这个例子中,myFunction被声明为noexcept,但它抛出了一个std::runtime_error异常。因为这是在一个noexcept函数中发生的异常,程序会立即调用std::terminate,而不会执行main函数中的catch块。

总结

  • noexcept声明:用于指示函数不会抛出异常。
  • 违反noexcept:如果在noexcept函数中抛出异常,程序会调用std::terminate
  • std::terminate行为std::terminate会立即终止程序的执行,不进行任何清理。

‌‌‌‌  通过使用noexcept,程序员可以在编译时和运行时获得更好的异常安全性保证,同时也能帮助编译器进行优化。但需要谨慎使用,确保在noexcept函数中确实不会有任何异常抛出。

368. vector中emplace back是什么?

‌‌‌‌  emplace_back是一种方法,用于在向量尾部直接构造和添加一个新元素,而无需额外的复制或移动操作。他接受的参数是将要添加的元素的构造函数参数,而不是已构造的元素本身。这个方法可以提高效率,因为省去了不必要的构造和析构过程。

369. 右值引用是怎么样的?如果没写右值引用的函数呢?

‌‌‌‌  右值引用是C++引入的一种引用类型用于绑定到临时对象(右值)。使用右值引用可以避免不必要的对象拷贝,从而提高效率。

‌‌‌‌  如果某个函数未提供右值引用版本,当需要传递临时对象作为参数时,会按照传统的拷贝或移动的方式处理,这可能会导致额外的拷贝开销。右值引用通过允许直接修改临时对象(通过移动语义),减少了这种不必要的拷贝,优化了性能

370. 在写webserver的时候,socket编程是阻塞的还是非阻塞的,边缘触发和水平触发的区别是什么?

‌‌‌‌  在编写webserver的时候,socket编程可以是阻塞的,也可以是非阻塞的,具体取决于你的需求和设计。阻塞socket会在没有数据可读的情况或者无法立即写入数据时使调用的线程阻塞,而非阻塞socket则不会

‌‌‌‌  边缘触发和水平触发是IO多路复用中的概念。水平触发(LT)模式下,只要socket处于可读或可写状态,无论是否有新的IO事件,都会触发通知。而边缘触发(ET)模式下,只有在状态发生改变时才会触发通知,比如从不可读写变为可读写时。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1559366.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

AI视频技术复活老照片-简单快捷

准备老照片 可在网上搜索“老照片”图片&#xff0c;选择人物背景全的图片 照片修复 腾讯的ARC Lab网站 https://arc.tencent.com/zh/ai-demos/faceRestoration 上传照片&#xff0c;修复后下载&#xff0c;会直接在浏览器中下载 AI视频生成 采用可灵网&#xff1a; http…

PGMP-05相关方

目录 1.主要内容 2.概括 3.相关方人员 1.主要内容 Stakeholders IdentificationStakeholders AnalysisStakeholders Engagement PlanningStakeholders EngagementStakeholder communications 2.概括 识别&#xff1a;产生相关方登记册&#xff0c;使用头脑风暴分析&#x…

深入理解Transformer的笔记记录(精简版本)----Seq2Seq → Seq2Seq with Attention

只要是符合类似的框架,都可以统称为 Encoder-Decoder 模型。 1、RNN RNN引入了隐状态h(hidden state)的概念,隐状态h可以对序列形的数据提取特征,接着再转换为输出。 x1,x2,x3,x4如: 自然语言处理问题。x1可以看做是第一个单词,x2可以看做是第二个单词,依次类推语音处…

2024 闽盾杯-黑盾赛道WP

CRYPTO 签到题-学会SM https://www.json.cn/encrypt/sm3 题目要求小写所以需要转换一下 或者脚本&#xff1a; import hashlib message "heidun2024" hash_object hashlib.new(sm3) hash_object.update(message.encode(utf-8)) hash_value hash_object.hexdigest(…

AI助力智慧农田作物病虫害监测,基于YOLOv9全系列【yolov9/t/s/m/c/e】参数模型开发构建花田作物种植场景下棉花作物常见病虫害检测识别系统

智慧农业是一个很大的应用市场&#xff0c;将当下如火如荼的AI模型技术与现实的农业生产场景相结合能够有效提升生产效率&#xff0c;农作物在整个种植周期中有很多工作需要进行&#xff0c;如&#xff1a;浇水、施肥、除草除虫等等&#xff0c;传统的农业作物种植生产管理周期…

带你走近CCV(一)

从事多媒体互动行业8年了&#xff0c;最近才想着自己可以独自写一个识别软件&#xff0c;应该说想把公司里的识别统统临摹一遍&#xff0c;这样在接外包的时候可以游刃有余了 什么是CCV&#xff1f; CCV是一个建立在openCV基础上的一个开源的架构&#xff0c;其全称是Communit…

SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(多数据源配置)

SpringBoot教程&#xff08;二十四&#xff09; | SpringBoot实现分布式定时任务之Quartz&#xff08;多数据源配置&#xff09; 前言多数据源配置引入aop依赖1. properties配置多数据源2. 创建数据源枚举类3. 线程参数配置类4. 数据源动态切换类5. 多数据源配置类HikariCP 版本…

Java基础(2) 之面向对象

文章目录 Java基础(2) 之面向对象1.对象2.类类的注意事项 3.this关键字4.构造器注意 5.封装性6.实体JavaBean实体类 7.成员变量和局部变量的区别8.staticstatic修饰成员变量static修饰成员方法static的注意事项工具类单例设计模式 9.代码块静态代码块实例代码块 10.继承权限修饰…

Springboot——使用poi实现excel动态图片导入解析

文章目录 前言依赖引入导入实现方式一方式二 前言 最近要实现一个导入导出的功能点&#xff0c;需要能将带图片的列表数据导出到excel中&#xff0c;且可以导入带图片的excel列表数据。 考虑到低代码平台的表头与数据的不确定性&#xff0c;技术框架上暂定使用Apache-POI。 …

java 自定义填充excel并导出

首先在resources下面放一个excel模板 1. 方法签名和请求映射 RequestMapping(value "/ExportXls") public ResponseEntity<byte[]> rwzcExportXls(HttpServletRequest request, RequestBody JSONArray jsonArray) throws IOException { RequestMapping(val…

ubuntu 开放 8080 端口快捷命令

文章目录 查看防火墙状态开放 80 端口开放 8080 端口开放 22端口开启防火墙重启防火墙**使用 xhell登录**&#xff1a; 查看防火墙状态 sudo ufw status [sudo] password for crf: Status: inactivesudo ufw enable Firewall is active and enabled on system startup sudo…

微服务实战——登录(普通登录、社交登录、SSO单点登录)

登录 1.1. 用户密码 PostMapping("/login")public String login(UserLoginVo vo, RedirectAttributes redirectAttributes, HttpSession session){R r memberFeignService.login(vo);if(r.getCode() 0){MemberRespVo data r.getData("data", new Type…

进阶功法:SQL 优化指南

目录标题 SQL 优化指南1. 插入数据优化1.1 批量插入数据1.2 手动提交事务1.3 主键顺序插入1.4 大批量插入数据步骤&#xff1a; 2. 主键优化主键设计原则拓展知识 3. ORDER BY 优化3.1 Using filesort3.2 Using index示例 3.3 ORDER BY 优化原则 4. GROUP BY 优化示例 4.1 GROU…

优雅的实现服务调用 -- OpenFeign

文章目录 1. RestTemplate存在问题2. OpenFeign介绍3. 快速上手引入依赖添加注解编写OpenFeign的客户端远程调用 4. OpenFeign参数传递从URL中获取参数传递单个参数传递多个参数传递对象传递JSON 5. 最佳实践Feign继承方式创建一个新的模块引入依赖编写接口打jar包服务实现方实…

javacpp调用pdfium的c++动态库

1、.h头文件 2、生成java代码的conf PdfiumDocumentConfigure.java package org.swdc.pdfium.conf;import org.bytedeco.javacpp.annotation.Platform; import org.bytedeco.javacpp.annotation.Properties; import org.bytedeco.javacpp.tools.InfoMap; import org.byte…

物联网:一种有能力重塑世界的技术

物联网&#xff08;IoT&#xff09;近年来对我们的日常生活产生了如此积极的影响&#xff0c;以至于即使是不懂技术的人也开始相信它所带来的便利以及敏锐的洞察力。 物联网是一场数字技术革命&#xff0c;其意义甚至比工业革命更为重大。物联网是仍处于起步阶段的第四次工业革…

SldWorks问题 2. 矩阵相关接口使用上的失误

问题 在计算三维点在图纸&#xff08;DrawingDoc&#xff09;中的位置时&#xff0c;就是算不对&#xff0c;明明就4、5行代码&#xff0c;怎么看都是很“哇塞”的&#xff0c;毫无问题的。 但结果就是不对。 那就调试一下吧&#xff0c;调试后发现生成的矩阵很不对劲&#…

电力设备图像分割系统源码&数据集分享

电力设备图像分割系统系统源码&#xff06;数据集分享 [yolov8-seg-efficientViT&#xff06;yolov8-seg-C2f-DCNV2等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI G…

分治算法(7)_归并排序_计算右侧小于当前元素的个数

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 分治算法(7)_归并排序_计算右侧小于当前元素的个数 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&…

鸿蒙微内核IPC数据结构

鸿蒙内核IPC数据结构 内核为任务之间的通信提供了多种机制&#xff0c;包含队列、事件、互斥锁、信号量等&#xff0c;其中还有Futex(用户态快速锁)&#xff0c;rwLock(读写锁)&#xff0c;signal(信号)。 队列 队列又称为消息队列&#xff0c;是一种常用于任务间通信的数据…