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

C++面试真题分享20260320

**目录

1、 指针和引用的区别 2
2、 函数内部返回指针和引用会怎么样 2
3、 一级指针、二级指针、三级指针的使用(举例说明) 3
4、 讲一下智能指针,实现原理是什么? 3
5、 C++四种命名的、更安全的类型转换运算符 4
6、 static、const 5
7、 什么是虚构函数,实现原理是什么 5
8、 为什么析构函数要设置为虚函数 6
9、 如果实例化一个类,编译器会生成哪些内容? 6
10、 使用过那些容器、什么时候选择使用那个 7
11、 QT元对象系统 7**

1、指针和引用的区别

特点:
指针是变量,指针本身占用内存,4字节或者8字节,指向的是对象的地址,其所指向的地址可变,地址里面存储的数据也可变,也可以为空(nullptr),使用之前需要进行判断,可以使用解引用符(*)来访问指针所指向的地址里面的值。
使用场景:
通常用于动态内存分配,数组操作和函数传参等
int x = 10;
int y = 90;
int *ptr = &x;
ptr = 99;//通过解引用符()修改其所指向地址中存放的数据
ptr = &y;//修改指针指向内容

特点:
引用是变量的别名,对引用的所有操作都直接作用于原变量,定义是就要初始化,并且在这个生命周期当中不能重新绑定到另一个变量,没有空引用的概念,引用通常不占用额外的内存。
使用场景:
通常用于函数传参、操作符重载以及创建别名等
int x = 10;
int &ref = x;
ref = 90 //x 的值被修改为90;

2、函数内部返回指针和引用会怎么样

1、返回局部变量的指针或者引用都是严重错误
int* badFunc()
{
int x = 10; // 栈上分配
return &x; // 函数结束x被销毁,返回悬垂指针
}
2、返回动态分布内存的指针,可以但是调用这需要注意释放,建议使用智能指针std::unique_ptr返回。
int* createArray(int size)
{
return new int[size]; // 调用者需记得delete[]
}

3、返回静态/全局变量或成员变量的引用是安全的
const std::string& getName()
{
static std::string name = “default”; // 静态生命周期
return name; // 安全
}

3、一级指针、二级指针、三级指针的使用(举例说明)

指针的层级反应了简介访问的深度,用于修改不同“级别”的数据
1、一级指针:修改所指向的内容
void setValue(int* p, int val)
{
*p = val; // 修改p指向的int
}

2、二级指针:修改指针本身
void createBuffer(char** buffer, int size)
{
buffer = new char[size]; // 修改外部指针
}
// 调用:
char
buf;
createBuffer(&buf, 1024);

3、三级指针:较少用,用于修改指向指针的指针
void resizeMatrix(int*** matrix, int newRows)
{
matrix = new int[newRows]; // 修改行指针数组
for(int i=0; i<newRows; i++)
(*matrix)[i] = new int[cols];
}

4、讲一下智能指针,实现原理是什么?

智能指针是基于RAII的自动化内存管理工具,核心原理是用栈对象的生命周期管理堆资源。
1、std::unique_ptr:独占所有权
提供对动态分配的单⼀对象所有权的独占管理。通过独占所有权,确保只有⼀个
std::unique_ptr 可以拥有指定的内存资源。
原理:禁用拷贝(=delete),只允许移动。析构时自动delete。
简化实现:
template
class SimpleUniquePtr {
T* ptr;
public:
~SimpleUniquePtr() { delete ptr; }
// 禁止拷贝
SimpleUniquePtr(const SimpleUniquePtr&) = delete;
// 允许移动
SimpleUniquePtr(SimpleUniquePtr&& other) : ptr(other.ptr) {
other.ptr = nullptr;
}
};
2、std::shared_ptr:共享所有权
允许多个智能指针共享同⼀块内存资源。内部使⽤引⽤计数来跟踪对象被共享的次数,当计数为零时,资源被释放。提供更灵活的内存共享,但可能存在循环引⽤的问题。
原理:引用计数。内部包含两个指针:指向对象、指向控制块。
控制块:包含引用计数器、弱引用计数器、删除器。
关键:引用计数增减是原子操作,保证线程安全。
3、std::weak_ptr:弱引⽤智能指针
⽤于解决 std::shared_ptr 可能导致的循环引⽤问题。
std::weak_ptr 可以从 std::shared_ptr 创建,但不会增加引⽤计数,不会影响资源的释放。通过 std::weak_ptr::lock() 可以获取⼀个 std::shared_ptr 来访问资源。

5、C++四种命名的、更安全的类型转换运算符

关键字:static_cast、dynamic_cast、reinterpret_cast和 const_cast
1、static_cast 最常用,用于良性转换
没有运⾏时类型检查来保证转换的安全性
进⾏上⾏转换(把派⽣类的指针或引⽤转换成基类表示)是安全的
进⾏下⾏转换(把基类的指针或引⽤转换为派⽣类表示),由于没有动态类型检查,所以是不安全的。
基本类型转换:double d = static_cast(i);
向上转型:Base* b = static_cast<Base*>(d);
非const转const

使⽤:

  1. ⽤于基本数据类型之间的转换,如把int转换成char。
  2. 把任何类型的表达式转换成void类型。
    2、dynamic_cast 安全向下转型
    在进⾏下⾏转换时,dynamic_cast具有类型检查(信息在虚函数中)的功能,⽐static_cast更安全。
    转换后必须是类的指针、引⽤或者void*,基类要有虚函数,可以交叉转换。
    dynamic本身只能⽤于存在虚函数的⽗⼦关系的强制类型转换;对于指针,转换失败则返回nullptr,对于引⽤,转换失败会抛出异常。
    3、const_cast 移除const/volatile
    常量指针转换为⾮常量指针,并且仍然指向原来的对象。常量引⽤被转换为⾮常量引⽤,并且仍然指向原来的对象。去掉类型的const或volatile属性。
    4、reinterpret_cast 低层重新解释
    最危险,如指针转整数、函数指针转换 几乎不用于应用程序开发,在驱动或特定库中使用

6、static、const

static:
1、静态局部变量:函数内只初始化一次,保持值
int getNextID() {
static int id = 0; // 只执行一次
return ++id;
}
2、静态成员变量:类所有对象共享,需类外定义
class Device {
static int deviceCount; // 声明
};
int Device::deviceCount = 0; // 定义
3、静态成员函数:属于类而非对象,不能访问非静态成员

const:
1、修饰变量:声明变量为常量,不可修改
2、修饰指针:
常量指针:const int* p:指向内容不可变
指针常量:int* const p:指针本身不可变
3、修饰成员函数:不能修改非静态的成员变量
4、修饰引用:const T&,常用作函数参数避免拷贝

7、什么是虚构函数,实现原理是什么

虚函数是实现运行时多态的机制,允许通过基类指针/引用调用派生类的覆盖函数。
1、虚函数表:每个含有virtual函数的class都有⼀个vtbl(虚函数表),vtbl中存储的是指向各个虚函数的函数指针;
2、虚表指针:每个对象内部有一个隐藏的vptr,指向其类的虚表。
3、内存布局
class Base { // 有虚函数
int data;
virtual void func1();
virtual void func2();
};
// 对象内存:[vptr][data…]
// vptr -> Base的虚表:[&Base::func1, &Base::func2]
4、当对象调⽤某个virtual函数的时候,编译器根据对象的vptr找到类的vtbl,在vtbl中寻找适当的函数指针
调用过程:
Base* b = new Derived();
b->func1(); // 实际是:(*b->vptr[0])()通过vptr找到虚表
通过偏移找到函数地址
调用该地址

8、为什么析构函数要设置为虚函数

当通过基类指针删除派生类对象时,如果基类析构函数非虚,会导致派生类部分内存泄漏。

9、如果实例化一个类,编译器会生成哪些内容?

实例化一个类时,编译器/运行时主要做以下事情:
1、内存分配:
栈上:编译器计算大小,调整栈指针
堆上:调用new运算符,底层是malloc

2、初始化过程(按顺序):
a. 如果有虚函数,设置vptr指向正确的虚表
b. 按声明顺序初始化成员变量:
基本类型:不初始化(随机值),除非在初始化列表
类类型:调用其构造函数
c. 执行构造函数体

3、特殊成员函数的生成:
如果没定义,编译器生成:
默认构造函数
拷贝构造函数
拷贝赋值运算符
析构函数
移动操作(C++11后)

10、使用过那些容器、什么时候选择使用那个

根据访问模式、操作频率、内存布局选择容器
容器 底层 关键特性 使用场景
vector​ 动态数组 连续内存,随机访问O(1),尾部插入快,中间插入慢 默认选择,存储B超图像帧序列
deque​ 分块数组 头尾插入O(1),随机访问较快 需要频繁头尾操作,如实时数据缓冲区
list​ 双向链表 任意位置插入O(1),内存不连续,无随机访问 极少用,除非需高频中间插入删除
map​ 红黑树 按键排序,查找O(log n) 需要有序遍历或范围查找,如有序配置表
unordered_map​ 哈希表 平均O(1)查找,无序 快速查找,如设备ID->控制器映射

11、QT元对象系统

Qt元对象系统是Qt框架实现信号槽、运行时类型信息、属性系统等高级特性的基石。它由三个核心部分组成:Q_OBJECT宏、元对象编译器moc、以及运行时支持库。
Q_OBJECT宏:在类声明中标记,表示这个类需要元对象系统支持
元对象编译器moc:在编译前扫描头文件,为含Q_OBJECT的类生成额外的.moc.cpp文件
QMetaObject类:运行时存储类的元信息(类名、方法、属性、信号槽等)

http://www.jsqmd.com/news/512533/

相关文章:

  • msjetoledb40.dll丢失损坏怎么办? 免费下载修复方法分享
  • Axios拦截器源码解析:从use方法到Promise链的完整执行流程
  • CCF-202412-T3缓存模拟90分
  • 巴西空运专线市场盘点:五大服务商助力中巴贸易 - 时事观察官
  • remove high frequency but keep low frequency
  • 20252918 2025-2026-2 《网络攻防实践》第1周作业
  • VMware 虚拟机安装--urbutun3种下载的镜像选择指南
  • Clawdbot优化升级:提升Qwen3:32B代理网关性能与稳定性的方法
  • 光伏PV三相并网逆变器MATLAB仿真模型:高效功率输出与稳定直流母线电压
  • RP2040嵌入式视觉平台:轻量级MIPI/并行摄像头采集方案
  • RP2350A开发板硬件设计与电源架构解析
  • msjint40.dll文件丢失不可怕 免费下载修复方法分享
  • 2026年上海房产律师推荐:房产继承分割难题高性价比律师与避坑指南 - 十大品牌推荐
  • 从Demo到实战:手把手教你定制Cartographer的Launch和Lua配置文件(Gazebo仿真版)
  • 手机号逆向查询QQ号:3步快速找回遗忘账号的终极指南
  • ESP32 cam (3)http协议 上传图片给电脑flask服务器 - MKT
  • 聊聊菲尔格林产品的优势,2026年干冰清洗机选购哪家好 - myqiye
  • IT 补丁管理的8大深坑,如何破解?
  • CNN架构解析:TranslateGemma模型中的卷积神经网络应用
  • 告别机械音!Qwen3-TTS实测:97ms低延迟生成真人级语音
  • 短视频种草新时代:传声港新媒体平台五大平台赋能品牌增长新引擎 - 博客湾
  • 刚学完苍穹外卖,大模型就杀到家门口了?传统后端开发何去何从,我该转型Agent吗?
  • 通义千问1.5-1.8B-Chat-GPTQ-Int4:Win11右键菜单改回Win10风格——操作指南与原理讲解
  • 讲讲2026年专业的欧亚联盟EAC认证机构,荣仪达有啥优势 - mypinpai
  • [特殊字符] GLM-4V-9B系统集成:与现有CRM系统的对接实践
  • MicroPython嵌入式开发实战:GPIO/UART/I2C外设控制与低功耗设计
  • 分析AI搜索优化,南方网通讯灵AI性价比和效果究竟如何? - 工业品网
  • STM32 + RTOS移植成功率提升300%的关键动作(基于ARM Cortex-M3/M4/M7的8项寄存器级校验清单,含MPU配置checklist)
  • 谁懂!京东e卡到底怎么用啊!!!
  • Swift面试题2024:从基础到高阶的全面解析