c++八股(可能问的多一点)
1.简单说说C++11语法特性
答:
1.auto以及decltype自动类型推导,避免手动声明复杂类型,减少冗长代码提升了可读性和安全性。
2.智能指针 自动释放内存
(具体说说)
有shared和unique 差异主要体现在所有权、内存开销、引用计数以及线程安全上。
(本质和实现原理)
智能指针本质是一个封装了一个原始C++指针的类模板,为了确保动态内存的安全性而产生的。实现原理是通过一个对象存储需要被自动释放的资源,然后依靠对象的析构函数来释放资源。
(说说shared和unique的区别)
3.nullptr来代替NULL来表示空指针,因为NULL实际上是整数0,而不是一个真正的指针类型,容易产生误导。
4.C++11中的移动语义和右值引用(T&&
)用于避免不必要的深拷贝,提高性能。它们允许对象的资源在右值或即将销毁的对象之间转移,而不是复制。例如,std::move
强制将对象转换为右值引用,从而实现高效的资源转移,减少内存分配和拷贝操作。移动构造函数和移动赋值运算符是实现这一功能的关键。
(为什么要引入右值引用?)右值引用是为一个临时变量取别名,它只能绑定到一个临时变量或表达式(将亡值)上。实际开发中我们可能需要对右值进行修改(实现移动语义时就需要)而右值引用可以对右值进行修改。
(左值引用和指针的区别?)
是否初始化:指针可以不用初始化,引用必须初始化 这里要区分初始化和声明的差异
本质不同:指针是一个变量,拥有自己的内存空间,引用是对被引用的对象取一个别名,引用和被引用对象占同一个空间。
5.lambda表达式
6.std::thread 多线程库的支持
7.范围for循环
2.说说面向对象的三大特性及其意义
封装 隐藏实现细节 实现模块化
继承 不修改类的情况下实现代码重用和扩展
多态 一个接口多种形态 为了代码扩展和重用性 分为静态多态和动态多态 分别用函数重载和虚函数重写实现
虚函数是怎么实现的?它存放在哪里在内存的哪个区?什么时候生成的
虚函数通过虚函数表和虚函数指针来实现的。虚函数表本质上就是一个由指针构成的数组,每个元素中的指针,即虚函数指针,会指向一个虚函数重写的实现代码。
虚函数表存放在静态存储区,在编译期就会生成。虚函数指针存放在实现该虚函数的对象的内存布局中,对象的内存是堆或栈,它就在哪里。
Static关键词的作用?
static 关键字有三个主要作用:
局部变量:在函数内部,static 局部变量只初始化一次,且在函数调用结束后仍然保留其值。
全局变量/函数:在文件内部,static 限制全局变量或函数的作用域,使其仅对当前文件可见。
类成员:在类中,static 成员变量或函数属于类本身而非某个对象,可以不通过对象访问(
int MyClass::count = 0;)。
贴个代码理解第三点:
#include <iostream>class MyClass {
public:// 静态成员变量,属于类本身static int count;// 构造函数,每创建一个对象,count 就增加1MyClass() {count++;}// 静态成员函数,用于访问或修改静态成员变量static void showCount() {std::cout << "Count: " << count << std::endl;}
};// 初始化静态成员变量
int MyClass::count = 0;int main() {// 在没有创建对象的情况下,直接通过类名访问静态成员函数MyClass::showCount(); // 输出: Count: 0MyClass obj1;MyClass obj2;// 可以通过类名或者对象访问静态成员obj1.showCount(); // 输出: Count: 2MyClass::showCount(); // 输出: Count: 2return 0;
}
typedef和define有什么区别?
typedef 用于定义类型别名,遵循编译器检查.#define 是预处理宏替换,直接文本替换,无类型检查。
简单说说final、extern、const、voliate的作用
final 防止继承 保证类不再扩展
extern 跨文件全局变量
const 定义常量
voliate 防止意外修改值 避免编译器优化
说说指针常量和常量指针
指针常量是指针本身是一个常量,指针指向的地址不可变 指向的对象值可以修改
常量指针是一个指向常量的指针,指向可以指向其他对象,指向的对象的值不可以改变
友元是什么?
友元(friend)是一个能够访问类的私有和保护成员的函数或类。
如何解决菱形继承的问题?
菱形继承发生在两个派生类从同一个基类继承,且最终有一个派生类同时继承两个派生类,导致重复继承
用虚基类,这样派生的是最后覆盖的虚函数。
如何将数据定义为寄存器变量?
关键字register register int a
有没有遇到内存泄漏的情况 如何处理的?
为什么不全用mmap分配内存?
mmap将文件映射到内存空间,作为一个系统调用的分配内存的手段,必然伴随着大量用户态和内核态的切换,这对小内存块的分配和释放非常不利,因此mmap知识和大内存块的分配
为什么不全用brk分配内存?
brk所操作的是堆的内存空间。堆内存分配往往会导致内存碎片,尤其是当内存频繁分配和释放时,连续的堆空间难以保持。这会影响性能。