C++ 面试题常用总结 详解(满足c++ 岗位必备,不定时更新)
📚 本文主要总结了一些常见的C++面试题,主要涉及到语法基础、STL标准库、内存相关、类相关和其他辅助技能,掌握这些内容,基本上就满足C++的岗位技能(红色标记为重点内容),欢迎大家前来学习指正,会不定期去更新面试内容。
Hi~!欢迎来到碧波空间,平时喜欢用博客记录学习的点滴,欢迎大家前来指正,欢迎欢迎~~
✨✨ 主页:碧波
📚 📚 专栏:C++ 系列文章![]()
目录
一、C ++ 语法基础
🔥 谈谈变量的使用和生命周期,声明和初始化
🔥 谈谈C++的命名空间的作用
🔥 include " " 和 <> 的区别
🔥 指针是什么?
🔥 什么是指针数组和数组指针
🔥 引用是什么?
🔥 指针和引用的区别
🔥 什么是函数指针和指针函数以及区别
🔥 什么是常量指针和指针常量以及区别
🔥 智能指针的本质是什么以及实现原理
🔥 weak_ptr 是否有计数方式,在那分配空间?
🔥 类型强制转换有哪几种?
🔥 函数参数传递时,指针、引用以及值传递有什么区别?
🔥 进程间的通信方式有那些?
🔥 线程间的通信方式有那些?
🔥 简单谈谈对线程的理解,线程间共享资源时该怎么处理?
🔥 常用关键字含义及其使用
🔥 const 可以修饰那些内容
🔥 class 和 struct 的区别?有了class 为啥仍还保留 struct?
二、标准库
🔥 什么是STL?
🔥 数组和vector的区别?
🔥 list 和 vector 的主要区别是什么?
🔥 在什么情况下使用 list 而不是 vector?
🔥 set 的底层数据结构是什么?
🔥 set 和 multiset 有什么不同?
🔥 map 和 unordered_map 的主要区别是什么?
三、内存
🔥 RAII是什么?
🔥 使用RAII的原因以及使用方法?
🔥 new 和 malloc 的区别?delete 和 free 的区别?
🔥 C++的内存框架分布情况
🔥 堆和栈的区别?
🔥 什么是内存对齐,内存对齐有什么好处?
🔥 什么是内存泄漏?写代码时应该怎么防止内存泄漏。
🔥 说说什么是深拷贝和浅拷贝?
四、类相关
🔥 讲讲C++的三大特性(封装、继承、多态)
🔥 多态是怎么实现的?
🔥 什么是虚函数和纯虚函数?以及区别?
🔥 虚函数是怎么实现的?虚函数在那个阶段生成?
🔥 构造函数和析构函数的作用?
🔥 构造函数和析构函数那个可以被声明为虚函数,为什么?
🔥 构造函数和析构函数那个可以被重载,为什么?
🔥 谈谈什么是重载、重写、隐藏?
🔥 this 指针,为什么会存在this指针?
五、其他必备
🔥 什么是git? 以及git常用命令
🔥 什么是svn? git 和 svn的区别
🔥 Linux 系统下常用的命令会那些,举例?
一、C ++ 语法基础
🔥 谈谈变量的使用和生命周期,声明和初始化
全局变量:在程序的任何地方都能访问到的变量,它们通常在整个程序执行期间都是有效的。
局部变量:定义在函数或者代码块内部的变量,它们只能在声明它们的函数或代码块内部访问
静态变量:一般是在变量前加static 进行声明。
如下表格是各变量之前的差异点,熟练掌握每种变量的属性,就可以正确使用变量。
各变量间的区别 | 全局变量 | 局部变量 | 静态全局 | 静态局部 |
声明方式 | 在函数外部声明,通常在文件的顶部或者在函数定义之外 | 在函数或代码块的开始部分声明 | 在变量声明时加上 static 关键字 | 在变量声明时加上 static 关键字 |
代码示例 | // 全局变量声明并初始化 int globalVar = 10; | void func() { // 局部变量声明并初始化 int localVar = 20; } | // 静态全局变量声明并初始化 static int globalVar = 10; | void func() { // 静态局部变量声明并初始化 static int localVar = 20; } |
初始化 | 在声明时初始化 | 建议在声明时初始化,避免未知错误 | 在声明时或者在第一次使用之前初始化 | 在声明时或者在第一次使用之前初始化 |
内存存储位置 | 存储在常量区(静态存储区) | 存储在栈区 | 存储在常量区(静态存储区) | 存储在常量区(静态存储区) |
作用域 | 整个文件都可访问 | 函数内部 | 整个文件都可访问 | 函数内部 |
生命周期 | 全局生命周期,会一直存在到程序结束 | 函数被调用期间 | 全局生命周期 | 具有全局生命周期,但作用域仍然受限于其声明的函数或代码块,保持其值在函数调用之间持久化 |
🔥 谈谈C++的命名空间的作用
命名空间
避免命名冲突: 可以帮助避免不同部分的代码中出现相同的名称,从而防止命名冲突。
组织代码: 可以将相关的函数、类等封装在一起,提高代码的组织性和可读性。
模块化开发: 可以将代码划分为不同的模块,使得代码更易于维护和扩展。
命名空间使用
namespace MyNamespace {int x;void func();
}
标准命名空间
// 通常需要加上 std:: 前缀,std::cout << "Hello, world!" << endl;// 或者使用 using namespace std;using namespace std;
cout << "Hello, world!" << endl;
🔥 include " " 和 <> 的区别
#include <文件名>
是包含标准库头文件的方式,编译器会按照标准路径顺序搜索。
#include "文件名"
是包含用户自定义或者项目内部头文件的方式,优先在当前目录查找,然后才是按照标准路径顺序搜索。
🔥 指针是什么?
指针是一个 用来存储变量地址 的特殊数据类型。简单来说,指针变量存储的是内存地址,而不是常规的值。通过指针,我们可以直接访问和操作内存中的数据,而不必知道实际存储的值是什么。
可以使用 解引用操作符 *
来访问指针所指向的变量,使用地址运算符 &
来获取变量的地址。
🔥 什么是指针数组和数组指针
指针数组是一个数组,其中的每个元素都是指针。这些指针可以指向不同的内存地址,通常用于存储一组相同类型的指针。
// ptrArray 是一个包含 5 个元素的数组,
// 每个元素都是 int* 类型的指针,可以分别指向不同的整数 int *ptrArray[5];
数组指针是一个指针,它指向数组的首地址。它本身是一个指针,但指向的内容是一个数组对象。
// arrPtr 是一个指针,指向一个包含 5 个整数的数组
int (*arrPtr)[5];
指针数组常用于需要动态管理一组指针的场景,而数组指针则用于处理数组的整体,特别是在函数参数传递和多维数组的处理中比较常见。
🔥 引用是什么?
引用提供了一个变量的别名。它使用 &
符号来定义。
// ref 是 num 的引用,即 ref 和 num 引用同一个内存位置的整数值int num = 10;
int &ref = num; // ref 是 num 的引用
- 引用必须在定义时初始化,并且一旦初始化后,它就不能再绑定到其他变量。
应用场景:
引用可以用于函数参数,允许在函数内部直接修改传递的变量,而不是复制一份值。
🔥 指针和引用的区别
引用不能指向空值(null),而指针可以。
引用在使用时不需要解引用操作(不需要 *
符号),而指针需要。
引用在定义时必须初始化,而指针可以在后续指向不同的对象。
🔥 什么是函数指针和指针函数以及区别
函数指针 是指 指向一个函数的指针变量。它可以指向一个特定类型和签名(参数类型和返回类型)的函数。函数指针的声明形式类似于指向其他类型的指针,但其类型是指向函数的指针类型。
// 声明一个函数指针类型
typedef void (*FuncPtr)(int); // FuncPtr 是一个指向返回类型为 void,参数为 int 的函数指针类型// 定义一个函数
void myFunction(int x) {// 函数体
}int main() {// 声明一个函数指针变量并初始化FuncPtr ptr = &myFunction;// 通过函数指针调用函数ptr(10); // 相当于调用 myFunction(10);return 0;
}
指针函数 指的是 返回类型 为 指向函数的指针 的函数。换句话说,指针函数是一个返回类型为函数指针的函数。
// 声明一个指针函数
int (*funcPtr)(int, int); // funcPtr 是一个函数,返回类型为 int*,参数为两个 int// 定义一个函数
int add(int a, int b) {return a + b;
}// 另一个函数,返回一个函数指针
int (*getAddFunctionPointer())(int, int) {return &add;
}int main() {// 获取 add 函数的函数指针funcPtr = getAddFunctionPointer();// 通过函数指针调用函数int result = funcPtr(3, 4); // 相当于调用 add(3, 4),result 等于 7return 0;
}
区别
函数指针是指指向函数的指针变量,而指针函数是一个返回类型为函数指针的函数。
函数指针在声明时需要指定其指向的函数的签名(参数类型和返回类型),而指针函数的返回类型是一个函数指针类型。
函数指针直接指向一个已存在的函数,可以通过该指针调用该函数;而指针函数返回一个函数指针,需要通过该函数指针再调用相应的函数。
🔥 什么是常量指针和指针常量以及区别
常量指针: 是指一旦指向了某个对象,就无法再指向其他对象的指针。
int x = 10;
int* const ptr = &x; // ptr 是一个常量指针,指向 int 类型的对象// 无法再修改 ptr 指向的对象,但可以修改对象本身的值
*ptr = 20; // 合法,修改了 x 的值为 20// 以下操作不合法,因为 ptr 是常量指针,不能改变指向
// ptr = &y; // 错误,无法改变 ptr 的指向
指针常量:是指指向常量对象的指针,一旦指向了某个对象,不能通过该指针修改所指向对象的值。
int x = 10;
const int* ptr = &x; // ptr 是一个指向常量 int 的指针// 以下操作合法,可以修改 ptr 所指向对象的值
x = 20; // 修改了 x 的值为 20// 以下操作不合法,因为 ptr 所指向的对象是常量,不能修改其值
// *ptr = 30; // 错误,不能通过 ptr 修改其指向的对象的值// 以下操作合法,因为 ptr 本身不是常量,可以改变其指向
int y = 50;
ptr = &y; // 合法,修改了 ptr 的指向为变量 y// 另一种写法 * 解引用,也是取值。int const * p;
区别
常量指针 强调指针本身是常量,指向对象的值可以改变;
指针常量 强调指针所指向的对象是常量,指针的指向可以改变
简单记忆:
距const 修饰右边最近的值是常量 ,不能被修改。
🔥 智能指针的本质是什么以及实现原理
智能指针是一种用于管理动态分配内存和自动释放资源的工具,其本质是利用了 RAII(资源获取即初始化)的设计模式。即在对象初始化的时候获取资源(比如动态分配的内存),在对象析构的时候自动释放资源。
它提供了一个封装了指针的对象,通过其析构函数来确保在对象生命周期结束时,所管理的资源能够被正确释放,避免内存泄漏和资源泄漏。
实现原理:
智能指针实现是引入计数引用机制。智能指针对象本身持有一个指向动态分配资源的指针,并维护一个引用计数。每当有一个新的智能指针指向同一块内存时,引用计数增加;当智能指针超出作用域或被显式销毁时,引用计数减少。当引用计数为零时,智能指针负责释放其管理的资源。
常见的智能指针类型:
std::shared_ptr:允许多个指针共享同一块资源,通过引用计数来管理资源的生命周期,适用于多个所有者的情况。
std::unique_ptr:独占所指向的对象,保证在任何时刻只有一个指针可以指向该对象,移动语义保证资源的所有权可以传递但不共享。
std::weak_ptr:用于协助 std::shared_ptr,不会增加引用计数,避免循环引用问题,通常用于解决 shared_ptr 的环状引用问题。
智能指针通过结合 RAII 设计模式和引用计数技术,提供了一种高效、安全、方便的动态内存管理机制,是现代 C++ 开发中推荐使用的重要工具之一。
🔥 weak_ptr 是否有计数方式,在那分配空间?
std::weak_ptr
是一种观测型智能指针,用于解决 std::shared_ptr
的循环引用问题,它本身并不进行内存空间分配或引用计数,而是依赖于 std::shared_ptr
来管理资源的生命周期。
std::weak_ptr 可以通过 std::lock() 成员函数获取一个 std::shared_ptr。
调用 std::lock()
成员函数可以获取一个 std::shared_ptr
对象,该对象指向 std::weak_ptr
所观测的对象(如果它仍然存在)。
如果 std::weak_ptr
过期(即其管理的对象已经被释放),std::lock()
返回一个空的 std::shared_ptr
。
#include <iostream>
#include <memory>int main() {std::shared_ptr<int> shared = std::make_shared<int>(42);std::weak_ptr<int> weak = shared;// 使用 std::lock() 获取 std::shared_ptrstd::shared_ptr<int> locked = weak.lock();if (locked) {// 如果成功获取到 std::shared_ptr,则可以安全地使用它std::cout << "Value pointed by shared_ptr: " << *locked << std::endl;} else {std::cout << "The shared_ptr is no longer available." << std::endl;}// 在此之后,shared_ptr 可能会超出作用域,对象被销毁return 0;
}
🔥 类型强制转换有哪几种?
有四种类型转换方式,它们分别是:
静态转换(static_cast)
常量转换(const_cast)
动态转换(dynamic_cast)
重新解释转换(reinterpret_cast)
🔥 函数参数传递时,指针、引用以及值传递有什么区别?
参数传递区别
值传递:复制实参的值给形参,函数内部操作的是副本,不影响原始值。
引用传递:形参是原始实参的别名,函数内部操作影响原始值。
指针传递:形参是原始实参的地址,函数内部通过解引用操作影响原始值。
🔥 进程间的通信方式有那些?
各种通信方式的详细介绍,参加 线程进程以及多线程多进程
管道
命名管道
消息队列
共享内存
信号量
套接字
🔥 线程间的通信方式有那些?
各种通信方式的详细介绍,参加 线程进程以及多线程多进程
共享内存
互斥锁
条件变量
🔥 简单谈谈对线程的理解,线程间共享资源时该怎么处理?
线程的详细介绍,参加 线程进程以及多线程多进程
线程(Thread)是操作系统调度的基本单位,是进程内的一条执行路径,每个进程至少包含一个线程。
线程间共享资源时,需要注意数据的一致性和并发访问的安全性,避免数据竞争和不可预料的结果。一般会采用 互斥锁 来避免多线程访问导致的资源调用错误。
🔥 常用关键字含义及其使用
static:关键字在不同上下文中有不同含义,主要用于:
静态变量:属于类或函数的静态存储区域,生命周期延续到程序结束。
静态函数:属于类的静态成员函数,与类的实例无关,可以直接通过类名访问。
const :用来声明常量。
常量变量:一旦初始化就不能修改的变量。
常量成员函数:在成员函数声明或定义中的 const
关键字表示该函数不会修改对象的状态。
sizeof: 是一个操作符,用于计算数据类型或变量的字节大小。
sizeof(type)
:返回类型或变量 type
所占的字节数。
例如:sizeof(int)
返回 int
类型的字节数,在大多数系统中是4个字节。
final:用于指示某个类、虚函数或者虚继承在派生时不可被继承或重写。
类:final class MyClass final { ... };
,表示该类不能被继承。
虚函数:virtual void myFunc() final;
,表示该虚函数在子类中不能被重写。
override:是C++11引入的关键字,用于 显式指示函数 是在派生类中覆盖了基类中的虚函数。
在派生类中重写基类的虚函数时,可以使用 override
关键字,以确保正确性和可读性。
virtual: 用于声明虚函数,即在基类中声明的函数,可以在派生类中被重写(override)
在基类中声明虚函数:virtual void foo();
派生类中可以选择重写基类的虚函数:void foo() override;
虚函数支持动态绑定,即在运行时根据对象的实际类型决定调用哪个版本的函数。
volatile: 用来声明一个变量是易变的,可能会被意外修改,通常用于多线程或者硬件相关的编程。
如:volatile int sensorValue;
,告诉编译器不要对 sensorValue
进行优化,因为它可能会在程序控制之外被改变。
explicit:用来声明构造函数为显式构造函数,防止隐式类型转换。
例如:explicit MyClass(int value);
,禁止编译器根据上下文进行隐式转换,必须显式调用构造函数。
inline:声明可以用于 函数定义 或者 成员函数 定义,建议编译器将 函数的代码插入到每个调用点处,而不是通过函数调用的方式进行调用。
如:inline int add(int a, int b) { return a + b; }
extern C 的作用
用于告诉编译器按照C语言的方式进行链接,主要用于解决C++代码和C代码混合编译的问题。
define 和 typedef 的区别
define: 用于定义宏,预处理阶段替换源代码中的标识符;
如:#define PI 3.14159
typedef : 用于给数据类型取别名。后续可以直接使用别名进行声明变量。
如:typedef unsigned int UINT; UINT num; // 等价于unsigned int num。
🔥 const 可以修饰那些内容
变量、指针和引用、函数、类对象或类指针、函数返回值。
🔥 class 和 struct 的区别?有了class 为啥仍还保留 struct?
class
和 struct
用来定义 类 和 结构体,主要区别在于默认的访问权限不同(class
默认私有,struct
默认公有)
它们的区别主要体现在 成员默认的访问权限 和 继承方式 上:
在 class
中,默认的成员访问权限是 private,
在 struct
中,默认的成员访问权限是 public
当没有显式指定继承方式时,class
默认是 private
继承,而 struct
默认是 public
继承。
虽然 class
和 struct
在语法上有一些细微差别,但其实它们提供了类似的功能。保留 struct
主要是为了提供语法上的灵活性和向后兼容性。
二、标准库
🔥 什么是STL?
STL 是 C++ 标准模板库的缩写。它是 C++ 标准库的一部分,提供了一组通用的模板类和函数,实现了常用的数据结构和算法,以及一些函数对象和迭代器概念,使得 C++ 程序员可以更加高效地进行编程。
容器
如 vector(动态数组)、deque(双端队列)、list(双向链表)、set(集合)、map(映射)等,这些容器提供了高效的数据存储和访问方式,各自适用于不同的需求和使用场景。
算法
如排序、搜索、合并等,这些算法独立于任何特定的容器类型,可以利用这些算法直接对容器进行操作。
迭代器
提供了一种统一的方式来遍历容器中的元素。
函数对象
即重载了函数调用操作符 ()
的对象。比如比较、排序等。
适配器
用于修改容器的接口或行为,使其能够满足特定的需求。
🔥 数组和vector的区别?
大小:数组的大小在创建时是固定的,而vector
的大小是动态可变的。
内存分配:数组的内存分配在栈上(静态数组)或堆上(动态数组),而vector
的内存总是动态分配的,通常在堆上。
功能:vector
提供了许多内置的操作,如动态扩展、插入和删除等,而数组只能直接访问元素,不支持动态调整大小。
性能:vector
在需要扩展时可能会重新分配内存,而数组的内存分配则不会改变。
🔥 list
和 vector
的主要区别是什么?
存储方式: list
是一个双向链表,而 vector
是一个动态数组。
访问时间: list
不支持常数时间的随机访问,vector
支持常数时间的随机访问。
插入和删除: 在 list
中,在任意位置插入或删除元素。而在 vector
中,不太适合在中间插入或删除元素。
🔥 在什么情况下使用 list
而不是 vector
?
当你需要在容器的中间频繁插入和删除元素,而不是在末尾插入或删除时,list
更适合。
当你不需要随机访问元素,而是需要频繁进行插入和删除操作时,list
是更好的选择,因为它的这些操作在常数时间内完成。
🔥 set
的底层数据结构是什么?
set
通常使用红黑树或其他自平衡的二叉搜索树实现。它确保所有元素是唯一的,并且保持排序状态,因此插入、删除和查找操作的时间复杂度是对数时间 (O(log n)
)。
🔥 set
和 multiset
有什么不同?
set
中的元素是唯一的,不能有重复的元素。
multiset
允许有重复的元素。
🔥 map
和 unordered_map
的主要区别是什么?
底层数据结构: map
通常使用红黑树或其他自平衡的二叉搜索树实现,而 unordered_map
使用哈希表实现。
访问时间: map
提供对数时间 (O(log n)
) 的查找、插入和删除操作,保持元素的排序。unordered_map
提供平均常数时间 (O(1)
) 的查找、插入和删除操作,但不保持元素的排序。
排序: map
中的元素是按照键的顺序排序的,而 unordered_map
中的元素没有特定的顺序。
三、内存
🔥 RAII是什么?
RAII 的核心思想是:资源的获取(如内存、文件句柄、网络连接等)与对象的初始化绑定在一起。具体来说,资源在对象的构造函数中获取,并在对象的析构函数中释放。
🔥 使用RAII的原因以及使用方法?
使用 RAII 的原因:
自动管理资源:利用对象的生命周期自动管理资源,避免忘记释放资源。
异常安全:即使发生异常,RAII 也能确保资源被正确释放,防止资源泄漏。
代码简洁:通过封装资源管理,减少代码重复和复杂性。
使用方法:
定义资源管理类:创建一个类,负责资源的分配和释放。
在构造函数中分配资源:例如,分配内存、打开文件等。
在析构函数中释放资源:确保资源在对象生命周期结束时得到释放。
🔥 new 和 malloc 的区别?delete 和 free 的区别?
new
:是 C++ 操作符,用于动态分配内存并调用构造函数。它会返回指向新分配内存的指针,并且可以用 delete
释放内存。new
会调用对象的构造函数初始化对象。
malloc
:是 C 标准库函数,用于动态分配内存,但不调用构造函数。它返回一个 void*
指针,需要强制转换为所需类型的指针。使用 malloc
分配的内存需要用 free
释放。
delete
:用于释放 new
分配的内存,并调用析构函数。对于数组使用 delete[]
。
free
:用于释放 malloc
分配的内存。free
不会调用析构函数。
int* p = new int(10); // 使用 new
delete p; // 使用 deleteint* q = (int*)malloc(sizeof(int)); // 使用 malloc
free(q); // 使用 free
🔥 C++的内存框架分布情况
C++ 的内存框架主要包括以下几个区域:
栈(Stack):用于存储局部变量和函数调用信息。栈内存分配速度快,但空间有限。
堆(Heap):用于动态分配内存。程序员可以控制分配和释放内存,但需要显式管理。内存的生命周期由程序员控制。
静态存储区(Static Storage Area):用于存储静态变量和全局变量。这些变量在程序运行期间一直存在。
常量区(Constant Data Area):用于存储常量数据,如字符串常量。
🔥 堆和栈的区别?
栈 | 堆 | |
分配方式 | 自动分配和释放 | 手动分配和释放(使用 new /malloc 和 delete /free )。 |
生命周期 | 函数调用时分配,函数返回时释放。 | 由程序员控制。 |
大小 | 通常较小(受限于栈大小)。 | 通常较大(受限于系统可用内存)。 |
速度 | 较快。 | 较慢(需要管理和合并空闲块)。 |
用途 | 局部变量、函数调用信息。 | 动态内存分配。 |
🔥 什么是内存对齐,内存对齐有什么好处?
内存对齐 是将数据结构的内存地址按某个特定的对齐边界(通常是数据类型的大小)进行排列。对齐可以提高内存访问效率,因为许多处理器在对齐的数据上访问更快。
好处:
提高性能:对齐的数据结构能更有效地利用缓存和减少内存访问时间。
防止错误:某些硬件架构要求数据必须对齐,否则会引发硬件异常或性能下降。
🔥 什么是内存泄漏?写代码时应该怎么防止内存泄漏。
内存泄漏 是指程序在动态分配内存后,没有释放这些内存,导致系统资源浪费并最终可能导致程序崩溃或变慢。
防止内存泄漏的方法:
使用 RAII:通过对象的生命周期自动管理资源。
智能指针:使用 std::unique_ptr
和 std::shared_ptr
管理动态内存,避免手动释放内存。
内存分析工具:使用工具如 Valgrind、AddressSanitizer 等检测和分析内存泄漏。
良好的编码实践:确保每个 new
都有对应的 delete
,每个 malloc
都有对应的 free
。
🔥 说说什么是深拷贝和浅拷贝?
浅拷贝
定义:复制对象时,只复制对象的指针值,而不复制指针指向的内容。结果是原始对象和拷贝对象共享相同的资源。
问题:修改一个对象的资源会影响到另一个对象,可能导致资源冲突和错误。
深拷贝
定义:复制对象时,创建对象指针指向的资源的完整副本。这样,原始对象和拷贝对象各自拥有自己的资源。
好处:避免共享资源带来的问题,保证对象的独立性。
四、类相关
🔥 讲讲C++的三大特性(封装、继承、多态)
封装:将数据(成员变量)和对数据的操作(成员函数)捆绑在一起,并对外部隐藏数据的具体实现。
继承:通过继承,子类可以继承父类的属性和行为,从而实现代码的重用和扩展。
多态:允许不同的对象以相同的接口进行操作,即同一操作可以作用于不同的对象上,表现出不同的行为。
🔥 多态是怎么实现的?
多态的实现主要依赖于虚函数和动态绑定。多态允许程序在运行时决定调用哪个具体的函数实现。
运行时多态:通过使用虚函数实现,允许基类指针或引用调用派生类中的重写函数。这是通过虚函数表(vtable)和虚指针(vptr)机制实现的。
🔥 什么是虚函数和纯虚函数?以及区别?
虚函数
定义:在基类中声明为 virtual
的成员函数,允许派生类重写(override)该函数。虚函数实现运行时多态。
作用:通过基类指针或引用调用虚函数时,实际调用的是派生类中的重写函数。
纯虚函数
定义:在基类中声明为 virtual
并且等于 0 的虚函数,例如 virtual void func() = 0;
。
作用:定义接口,要求所有派生类必须实现纯虚函数。使得基类成为抽象类,不能实例化。
🔥 虚函数是怎么实现的?虚函数在那个阶段生成?
虚函数表(vtable):每个类(如果包含虚函数)会有一个虚函数表,它是一个指向虚函数实现的指针数组。每个对象会有一个指向虚函数表的指针(vptr)。
动态绑定:通过 vptr 指针,运行时可以查找虚函数表中的具体函数地址,决定调用哪个函数实现。
生成阶段:
编译阶段:编译器生成虚函数表和虚指针。虚函数表在类定义时生成,虚指针在对象实例化时设置。
🔥 构造函数和析构函数的作用?
构造函数
作用:在创建对象时初始化对象的状态。构造函数可以用于分配资源、初始化数据成员等。
特性:构造函数与类名相同,无返回值,可以被重载。
析构函数
作用:在对象生命周期结束时清理对象的资源。析构函数负责释放构造函数分配的资源,如内存、文件句柄等。
特性:析构函数的名字前加 ~
,无返回值,不能被重载。
🔥 构造函数和析构函数那个可以被声明为虚函数,为什么?
析构函数可以被声明为虚函数:如果基类的析构函数是虚函数,确保派生类的析构函数在基类指针或引用被销毁时正确调用。防止资源泄漏和不完全析构。
构造函数不能被声明为虚函数:构造函数在对象创建时调用,此时对象还未完全构造,无法设置虚函数表,因此构造函数不能是虚函数。
🔥 构造函数和析构函数那个可以被重载,为什么?
析构函数不可以被重载:每个类只能有一个析构函数,负责对象生命周期结束时的清理操作。如果允许重载,会导致析构时不确定性。
构造函数可以被重载:允许创建对象时通过不同的参数进行初始化。通过重载构造函数,可以提供多种初始化方式。
🔥 谈谈什么是重载、重写、隐藏?
重载:同一作用域内多个函数名相同但参数列表不同。
覆盖:派生类重写基类的虚函数,提供特定实现。
重定义:派生类中定义了与基类同名但参数列表不同的函数,导致基类函数不可见。
🔥 this 指针,为什么会存在this指针?
定义:this
指针是指向当前对象的指针。在类的成员函数内部,this
指针指向调用该函数的对象。
访问对象成员:允许成员函数访问对象的属性和其他成员函数。
区分成员变量和参数:在成员函数中,this
指针可以用来区分同名的成员变量和函数参数。
实现链式调用:可以返回 *this
实现链式调用。
五、其他必备
🔥 什么是git? 以及git常用命令
Git 是一个分布式版本控制系统,用于跟踪文件的更改,特别是源代码。它允许多人协作开发,通过分支和合并功能管理项目的不同版本和特性。
git常用命令:
git clone [url]
:克隆远程仓库到本地。git add [file]
:将文件添加到暂存区。git commit -m "message"
:提交更改到本地仓库,-m
用于添加提交信息。git status
:查看工作目录和暂存区的状态。git diff
:查看文件的更改内容。git remote add [name] [url]
:添加远程仓库。git fetch [remote]
:从远程仓库获取最新的更改,但不合并。git pull
:从远程仓库获取并合并更改。git push
:将本地提交推送到远程仓库。git log
:查看提交历史。git revert [commit]
:撤销指定提交,但保留历史记录。git reset [commit]
:重置当前分支到指定提交。
🔥 什么是svn? git 和 svn的区别
SVN 是一个集中式版本控制系统,用于跟踪文件的更改和管理版本。与 Git 不同,SVN 采用集中式存储模式,所有版本历史都存储在中央服务器上。
git 一般用于存放代码,svn一般用于存放文档等。
🔥Linux 系统下常用的命令会那些,举例?
ls
:列出目录内容。cd [dir]
:切换目录。pwd
:显示当前工作目录。cp [source] [destination]
:复制文件或目录。mv [source] [destination]
:移动文件或目录。rm [file]
:删除文件,rm -r [dir]
删除目录及其内容。cat [file]
:显示文件内容。vim [file]
:使用 Vim 编辑器编辑文件。chmod [permissions] [file]
:改变文件权限。chown [owner]:[group] [file]
:改变文件所有者和组。ps
:显示当前进程。top
:实时显示系统进程和资源使用情况。df -h
:显示文件系统的磁盘使用情况。du -sh [dir]
:显示目录的大小。kill [pid]
:结束进程,pid
是进程ID。ping [host]
:测试网络连接。ifconfig
或ip a
:显示网络接口信息。netstat
:显示网络状态和端口使用情况。
相关文章:

C++ 面试题常用总结 详解(满足c++ 岗位必备,不定时更新)
📚 本文主要总结了一些常见的C面试题,主要涉及到语法基础、STL标准库、内存相关、类相关和其他辅助技能,掌握这些内容,基本上就满足C的岗位技能(红色标记为重点内容),欢迎大家前来学习指正&…...

LVS实验——部署DR模式集群
目录 一、实验环境 二、配置 1、LVS 2、router 3、client 4、RS 三、配置策略 四、测试 1.Director服务器采用双IP桥接网络,一个是VPP,一个DIP 2.Web服务器采用和DIP相同的网段和Director连接 3.每个Web服务器配置VIP 4.每个web服务器可以出外网…...

pythonUI自动化008::allure测试报告(安装及应用)
allure报告预览 1 下载jdk,配置jdk Path变量: https://www.cnblogs.com/FBGG/p/15103119.html(这里不作阐述,请看该偏文章配置即可) 2 下载allure驱动,配置allure Path变量: 下载allure驱动&a…...

常用的 git 和 linux 命令有哪些?
对于 Git 命令: 1. git init:初始化一个新的 Git 仓库。 2. git clone:克隆一个远程仓库到本地。 3. git add:将文件添加到暂存区。 4. git commit:提交暂存区的更改。 5. git status:查看工作区和暂存…...

MYSQL 删除一个字段前,判断字段是否存在
开发过程中经常需要提交可以重复执行的sql,当设计到需要增加字段时,可以参考如下办法: 1.如果是mysql 版本高于5.7.5 ALTER TABLE table_name DROP COLUMN IF EXISTS column_name; 2.通用方法 写一个存储过程,然后用存储过程取…...

vulnstack-5
环境搭建 靶场虚拟机共用两个,一个外网一个内网,用来练习红队相关内容和方向,主要包括常规信息收集、Web攻防、代码审计、漏洞利用、内网渗透以及域渗透等相关内容学习。 虚拟机密码 win7 sun\heart 123.com sun\Administrator dc123.com # …...

回归预测|基于灰狼优化GWO-Transformer-BiLSTM组合模型的数据回归预测Matlab程序 多特征输入单输出
回归预测|基于灰狼优化GWO-Transformer-LSTM组合模型的数据回归预测Matlab程序 多特征输入单输出 文章目录 前言回归预测|基于灰狼优化GWO-Transformer-BiLSTM组合模型的数据回归预测Matlab程序 多特征输入单输出GWO-Transformer-BiLSTM 一、GWO-Transformer-BiLSTM模型二、实验…...

STM32的USB接口介绍
STM32 USB接口是STM32微控制器系列中集成的一种通信接口,它允许STM32微控制器与外部设备或计算机进行高速的数据传输和通信。以下是STM32 USB接口的简要介绍: 1. 接口类型 STM32的USB接口通常支持USB 2.0标准,部分高端型号可能还支持USB 3.…...

【中等】 猿人学web第一届 第2题 js混淆 动态cookie 1
目录 调试干扰Hook Function 加密参数定位hook Cookie AST 解混淆字符串解密还原解密函数AST 配合解密函数还原字符串 ASCII 编码字符串还原字符串相加花指令(对象)剔除无用代码虚假 if剔除无引用代码剔除无引用的对象数值还原 switch 还原完整的 AST 代码代码注意 还原加密 请…...

ubuntu 22.04 安装 docker(服务器从毛胚到精装)
1、用户操作 阿里云默认是 root 用户,我们一般要自己创建一个用户,然后给该用户 sudo 权限 添加用户 sudo adduser newUserName赋予sudo权限 sudo usermod -aG sudo newUserName删除用户 sudo deluser --remove-home --remove-all-files newUserNam…...

Vue3从零开始——如何巧妙使用setup语法糖、computed函数和watch函数
文章目录 一、setup语法糖二、computed函数2.1 computed的基本用法2.2 computed vs methods2.3 注意事项 三、watch函数3.1 watch的基本用法3.2 immediate和deep选项 四、综合小Demo五、总结 一、setup语法糖 之前我们在编写代码时每次都要编写setup() ,默认导出配置&#x…...

【C++】 特殊类设计:从构思到实现,引领设计新潮流
🌈 个人主页:Zfox_ 🔥 系列专栏:C从入门到精通 目录 🚀 前言 一: 🔥 不能被拷贝的类 二: 🔥 只能在堆上创建对象的类 三: 🔥 只能在栈上创建对象的…...

性能调优 18. Tomcat整体架构及其设计精髓分析
1. Tomcat介绍 1.1. 介绍 这边使用的是Tomcat9来做说明,本章节先对Tomcat架构和设计有个整体认识。后续章节会对Tomcat性能调优做说明。 官方文档介绍 https://tomcat.apache.org/tomcat-9.0-doc/index.html1.2. Tomcat概念 …...

【C++高阶】:特殊类设计和四种类型转换
✨ 人生如梦,朝露夕花,宛若泡影 🌏 📃个人主页:island1314 🔥个人专栏:C学习 ⛺️ 欢迎关注:👍点赞 👂&am…...

kafka基础概念二
1.Kafka中主题和分区的概念 1.主题Topic 主题-topic在kafka中是一个逻辑的概念,kafka通过topic将消息进行分类。不同的topic会被订阅该topic的消费者消费 但是有一个问题,如果说这个topic中的消息非常非常多,多到需要几T来存,因…...

牛客-热身小游戏
题目链接:热身小游戏 第一种写法:线段树 介绍第二种写法:并查集 对于一些已经查询过的点,我们可以往后跳,进行路径压缩,他们的父亲为下一个点。 a数组记录[ l , r ] 之间的乘积,初始值为1。…...

Python 深度学习调试问题
Python–深度学习解决的常见问题 1.在自己写测试样例的时候,有时候可能将要传入的是input_size,不小心传入为input_dim,这个时候会导致出现问题,自定义的卷积模块或者池化等模块会提示类型问题。 解决的策略是: 1.进行assert i…...

linux恶意请求
nginx访问日志: 162.243.135.29 - - [05/Jan/2024:00:12:07 0800] "GET /autodiscover/autodiscover.json?zdi/Powershell HTTP/1.1" 404 153 "-" "Mozilla/5.0 zgrab/0.x"107.151.182.54 - - [04/Mar/2024:11:30:06 0800] "G…...

Java 反射笔记总结(油管)
Java系列文章目录 IDEA使用指南 Java泛型总结(快速上手详解) Java Lambda表达式总结(快速上手详解) Java Optional容器总结(快速上手图解) Java 自定义注解笔记总结(油管) Jav…...

HTML表格、表单、标签、CSS、选择器
目录 一、HTML表格 二、表单 三、布局标签 四、CSS 五、选择器 一、HTML表格 table:表格 tr:行 td:单元格;rowspan:纵向合并相邻单元格;clospan:横向合并相邻单元格 th:单元格加粗居中 border&…...

【javaWeb技术】·外卖点餐小程序(脚手架学习1·数据库)
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀系统学javaWeb开发_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 【免费】项…...

LVS 实现四层负载均衡项目实战--DR模式
一、环境准备 主机名IP地址router eth0:172.25.254.100 eth1:192.168.0.100 clienteth0:172.25.254.200lvseth1:192.168.0.50web1web2 1、client配置 [rootclient ~]# cat /etc/NetworkManager/system-connections/eth0.nmconne…...

Python与Qt的对应版本
Python与Qt的对应版本并没有严格的一一对应关系,但通常在使用Python与Qt进行开发时,会选择一个兼容性较好的版本组合。Qt的Python绑定库主要是PyQt和PySide,以下是几个常见的搭配: 1. **PyQt5**: - Python 3.5及以上版…...

WPF篇(12)-Image图像控件+GroupBox标题容器控件
Image图像控件 Image也算是独门独户的控件,因为它是直接继承于FrameworkElement基类。 Image控件就是图像显示控件。Image类能够加载显示的图片格式有.bmp、.gif、.ico、.jpg、.png、.wdp 和 .tiff。要注意的是,加载.gif动画图片时,仅显示第…...

LeetCode 热题 HOT 100 (024/100)【宇宙最简单版】
【哈希表】No. 0128 最长连续序列【中等】👉力扣对应题目指路 希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&am…...

如何在AWS上进行 环境迁移
在 AWS 上进行环境迁移通常包括以下几个步骤和最佳实践: 1. 评估和规划 评估当前环境:审查现有的应用程序、数据库、网络架构和依赖关系。确定迁移目标:明确迁移的目标(如成本节约、性能提升、可扩展性等)。选择迁移策略:根据应用程序的类型和复杂性,选择合适的迁移策略…...

云服务器和物理服务器的优缺点对比
云服务器优点在于灵活性强、成本效益高、易于扩展且支持全球化部署;缺点则包括安全性与可控性相对较弱,性能可能受限,以及存在服务中断风险。物理服务器则以其高性能、高稳定性、强安全性和完全可控性著称,但成本较高、扩展性受限…...

postgreSQL16添加审计功能
下载审计插件 https://github.com/pgaudit/pgaudit/releases他的分支版本支持不同的PGSQL按需下载 编译安装审计插件 tar -xvf pgaudit-16.0.tar.gzmake install USE_PGXS1 PG_CONFIG/app/postgresql/bin/pg_config启用postgreSQL审计功能 修改配置文件# 启用 pgAudit shar…...

如何应用OceanBase 的实时SQL诊断,解决AP场景下的痛点
随着数据量的快速增长与用户需求的变化,数据库的管理与优化工作日益凸显其重要性。作为DBA及开发者,您是否曾面临以下挑战: ○ 分析场景下,在处理大规模数据的且耗时较长的查询是,常涉及海量数据的处理及复杂的计算&…...

【数据结构】—— 栈
一、栈的基本概念1、栈的定义2、栈的常见基本操作 二、栈的顺序存储1、栈的顺序存储结构2、顺序栈存储实现(1)初始化(2)判空(3)进栈(4)出栈(5)取栈顶元素&…...