当前位置: 首页 > news >正文

C++面试模拟01

第一部分:基础知识

  1. :解释 const 关键字的作用,以及在什么场景下你会使用 const

  2. :在 C++ 中,newmalloc 的区别是什么?

  3. :请解释什么是“深拷贝”和“浅拷贝”?在什么情况下我们需要进行深拷贝?

  4. :C++ 中的引用和指针有什么区别?各自的使用场景是什么?


第二部分:面向对象编程

  1. :请解释 C++ 中的“继承”和“多态”。可以举例说明如何实现多态吗?

  2. :假设你有一个基类 Shape 和派生类 CircleRectangle。如何设计一个类层次结构来支持多态调用?请写出代码示例。

  3. :C++ 支持多重继承(multiple inheritance),但是它可能会带来问题。请解释这些问题并说明如何使用虚继承来解决其中一个问题。


第三部分:STL(标准模板库)

  1. :C++ 标准库中的 std::vectorstd::list 有什么区别?分别适用于什么场景?

  2. std::mapstd::unordered_map 的区别是什么?它们的时间复杂度分别是多少?

  3. :在什么情况下你会使用 std::deque 而不是 std::vectorstd::list


第四部分:并发与多线程

  1. :请解释 C++ 中的多线程机制。如何使用 std::thread 创建线程?请写出代码示例。

  2. :什么是互斥锁(Mutex)?如何在 C++ 中使用它来保护共享资源?

  3. :什么是条件变量(Condition Variable)?请简要描述它的使用场景。


第五部分:C++ 高级特性

  1. :C++11 引入了移动语义(Move Semantics)。请解释移动语义的作用以及它与复制语义的区别。

  2. :什么是 RAII(资源获取即初始化)?为什么在 C++ 中非常重要?

  3. :C++20 引入了协程(Coroutines)。你能描述一下协程的基本概念和使用场景吗?


第六部分:现场编程

  1. :写一个函数,接收一个整数数组,移除所有重复的元素,并返回不重复的元素个数。请尽可能优化时间复杂度和空间复杂度。
int removeDuplicates(std::vector<int>& nums);

 我的想法:

        1.如果给了nums里int的范围,可以使用哈希法去重

        2.没有范围或者范围太大,使用力扣里的“移除元素”的方法,操作双指针。先排序。

  1. :请写一个单例模式(Singleton Pattern)的实现。保证线程安全。

结束问题

  1. :在你的开发经历中,是否遇到过多线程的竞争条件?你是如何解决的?

  2. :你平时如何优化代码性能?有哪些常用的工具和方法?

C++知识点/面试问题指南-CSDN博客

newmalloc 的区别

  • 类型检查

    • new:会调用构造函数,分配内存时会执行类型检查。
    • malloc:不执行类型检查,返回 void* 类型的指针,需要手动转换类型。
  • 返回类型

    • new:返回指定类型的指针,不需要类型转换。
    • malloc:返回 void*,需要显式进行类型转换。
  • 异常处理

    • new:如果分配失败,会抛出 std::bad_alloc 异常。
    • malloc:如果分配失败,返回 NULL,需要手动检查。
  • 构造/析构函数

    • new:调用构造函数,负责初始化对象。
    • malloc:只分配内存,不会调用构造函数。
  • 释放内存

    • new:使用 delete 释放内存,并调用析构函数。
    • malloc:使用 free 释放内存,不会调用析构函数。

引用和指针的区别

  • 引用(Reference)

    • 引用是某个变量的别名,必须在声明时进行初始化,之后不能更改引用的对象。
    • 语法简单、直观,不需要解引用操作符(*)。
    • 一旦绑定到某个对象,就不能重新绑定。
  • 指针(Pointer)

    • 指针是存储内存地址的变量,可以指向任意对象或 NULL,可以在运行时改变所指向的对象。
    • 需要使用解引用操作符(*)来访问指向的对象。
    • 指针可以被重新分配、动态分配内存,使用更加灵活。
  • 区别

    • 引用不能为空,指针可以为空。
    • 引用一旦绑定,不能更改;指针可以在运行时改变指向的对象。
    • 引用更适合用于参数传递,指针更适合需要动态管理内存的场景。
  • 使用场景

    • 引用适用于函数参数传递和返回值,当你想避免拷贝数据时,通常使用引用。
void foo(int& ref);  // 引用传递

指针适用于需要动态分配内存的场景,或者需要改变指向的对象。

int* ptr = new int(5);  // 动态分配内存

C++ 中的“继承”和“多态”

  • 继承

    • 继承是一种面向对象编程的机制,允许从一个现有的类(基类/父类)创建一个新类(派生类/子类),以复用基类的成员变量和成员函数。

    • 继承可以让派生类拥有基类的属性和方法,并且可以扩展新的方法或重写基类的方法。

多态

  • 多态是指相同的函数或运算符在不同的对象上表现出不同的行为。C++ 支持编译时多态(通过函数重载和运算符重载)和运行时多态(通过虚函数实现)。

  • 多态使得程序能够通过基类的指针或引用来调用派生类的实现,从而实现灵活性。

  • 示例(虚函数实现多态):

class Base {
public:virtual void show() { std::cout << "Base class" << std::endl; }
};class Derived : public Base {
public:void show() override { std::cout << "Derived class" << std::endl; }
};void func(Base& obj) {obj.show();  // 会根据传入的对象类型调用相应的 show() 方法
}

设计 ShapeCircleRectangle 类层次结构

#include <iostream>
#include <cmath>class Shape {
public:virtual double area() const = 0;   // 纯虚函数,表示该类是抽象类virtual ~Shape() {}                // 虚析构函数
};class Circle : public Shape {
private:double radius;
public:Circle(double r) : radius(r) {}double area() const override {     // 实现多态return M_PI * radius * radius;}
};class Rectangle : public Shape {
private:double width, height;
public:Rectangle(double w, double h) : width(w), height(h) {}double area() const override {return width * height;}
};int main() {Shape* shapes[2];shapes[0] = new Circle(5.0);shapes[1] = new Rectangle(4.0, 6.0);for (int i = 0; i < 2; i++) {std::cout << "Area: " << shapes[i]->area() << std::endl;delete shapes[i];  // 注意内存管理}return 0;
}

C++ 中的多重继承问题及虚继承

  • 多重继承的问题
    • 二义性问题:当一个类同时继承自两个具有同名成员的基类时,派生类会出现二义性。

    • 菱形继承问题:在多重继承中,如果一个类从两个基类派生,而这两个基类又继承自同一个基类,派生类会继承两份相同的基类成员,这就造成了冗余数据和二义性问题。

    • 菱形继承示例

class A {
public:void show() { std::cout << "A's show" << std::endl; }
};class B : public A {};
class C : public A {};class D : public B, public C {};  // D 继承了两份 A 类的成员
  • 虚继承的解决方案:使用虚继承解决菱形继承问题,确保派生类只继承一份基类的成员。

  • 虚继承示例

class A {
public:void show() { std::cout << "A's show" << std::endl; }
};class B : virtual public A {};    // 虚继承
class C : virtual public A {};    // 虚继承class D : public B, public C {};  // D 只继承一份 A 的成员

 解释:通过 virtual 关键字,B 和 C 虚继承自 A,D 类中只有一份 A 类的成员,避免了二义性和数据冗余问题。

std::vectorstd::list 的区别

  • 底层实现

    • std::vector:基于动态数组实现,元素在内存中是连续存储的。
    • std::list:基于双向链表实现,元素在内存中是非连续存储的。
  • 时间复杂度

    • 访问vector 支持常数时间的随机访问(O(1)),因为其元素是连续存储的;而 list 访问任意位置的元素都需要线性时间(O(n))。
    • 插入/删除list 在任何位置插入或删除元素的时间复杂度为常数时间(O(1)),而 vector 在尾部插入/删除元素的时间复杂度为 O(1),但在中间插入或删除元素时需要移动数据,时间复杂度为 O(n)
  • 适用场景

    • std::vector:适用于需要频繁随机访问元素,或在末尾插入、删除元素的场景。
    • std::list:适用于需要频繁在中间插入或删除元素的场景,但不需要随机访问。

std::mapstd::unordered_map 的区别

  • 底层实现

    • std::map:基于红黑树(自平衡二叉搜索树)实现,键值对按键的顺序存储。
    • std::unordered_map:基于哈希表实现,键值对无序存储。
  • 时间复杂度

    • std::map:插入、删除、查找的平均时间复杂度为 O(log n)
    • std::unordered_map:插入、删除、查找的平均时间复杂度为 O(1),最坏情况下为 O(n)
  • 适用场景

    • std::map:适用于需要按键排序的场景。
    • std::unordered_map:适用于对性能要求较高、且不需要排序的场景。

何时使用 std::deque 而不是 std::vectorstd::list

  • std::deque:双端队列(double-ended queue),在两端插入和删除元素的时间复杂度为 O(1),并支持常数时间的随机访问。

  • 使用场景

    • 当需要在容器的两端频繁进行插入和删除操作,同时还需要随机访问时,使用 std::deque 是最好的选择。

    • std::vector 不同,deque 支持在头部进行高效的插入和删除操作。

    • std::list 不同,deque 支持随机访问。

RAII(Resource Acquisition Is Initialization,资源获取即初始化)是一种重要的 C++ 编程习惯,确保资源的正确管理。RAII 的核心思想是:将资源的生命周期绑定到对象的生命周期。当对象被创建时获取资源,当对象被销毁时释放资源。

  • 优点

    1. 自动管理资源:资源的分配和释放与对象的生命周期绑定,避免资源泄漏(如内存泄漏、文件句柄泄漏)。
    2. 异常安全:如果在资源使用过程中发生异常,RAII 确保在栈展开时资源会被正确释放。
    3. 简化代码:RAII 自动处理资源的释放,减少手动管理资源的复杂性。
  • 常见场景

    1. 内存管理:智能指针(如 std::unique_ptrstd::shared_ptr)通过 RAII 管理动态分配的内存。
    2. 文件管理std::fstream 等标准库类通过 RAII 确保文件在对象销毁时自动关闭。
  • 示例

class FileHandler {
private:FILE* file;
public:FileHandler(const char* filename) {file = fopen(filename, "r");if (!file) {throw std::runtime_error("File open failed");}}~FileHandler() {if (file) {fclose(file);  // 确保文件关闭}}
};

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 三维点云处理(C++)学习记录——PDAL
  • 【git】
  • Mysql基础——DML
  • mysql Field ‘ssl_cipher‘ doesn‘t have a default value的解决
  • OpenFeign:Spring Cloud中的声明式HTTP客户端
  • 2024年汉字小达人区级自由报名备考冲刺:今年官方模拟题练一练
  • SpringSecurity 5
  • 2024.9.18
  • Collections.synchronizedList()
  • 课程首发 | 微软 AI 创新日推荐官招募中
  • General OCR Theory: Towards OCR-2.0 via a Unified End-to-end Model
  • 如何使用ssm实现基于vue.js的购物商场的设计与实现+vue
  • git push命令报错:the remote end hung up unexpectedly
  • 【Transformer深入学习】之一:Sinusoidal位置编码的精妙
  • 升降梯人数识别摄像机
  • ComponentOne 2017 V2版本正式发布
  • const let
  • ECS应用管理最佳实践
  • JAVA_NIO系列——Channel和Buffer详解
  • JavaScript 基础知识 - 入门篇(一)
  • JAVA并发编程--1.基础概念
  • KMP算法及优化
  • Laravel 实践之路: 数据库迁移与数据填充
  • Material Design
  • MaxCompute访问TableStore(OTS) 数据
  • Promise面试题,控制异步流程
  • SQLServer之索引简介
  • 百度小程序遇到的问题
  • 测试如何在敏捷团队中工作?
  • 简单数学运算程序(不定期更新)
  • 世界上最简单的无等待算法(getAndIncrement)
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 移动端 h5开发相关内容总结(三)
  • 仓管云——企业云erp功能有哪些?
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • #单片机(TB6600驱动42步进电机)
  • $.each()与$(selector).each()
  • (09)Hive——CTE 公共表达式
  • (3)医疗图像处理:MRI磁共振成像-快速采集--(杨正汉)
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (剑指Offer)面试题34:丑数
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (一)SpringBoot3---尚硅谷总结
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)Oracle 9i 数据库设计指引全集(1)
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • .NET CF命令行调试器MDbg入门(一)
  • .net core Redis 使用有序集合实现延迟队列
  • .NET Core 实现 Redis 批量查询指定格式的Key