C++八股文(基础知识篇1)
1. C++ 和 C 有什么区别?
C++是C语言的超集,主要区别在于:
- 编程范式:C是面向过程的,C++支持面向对象、泛型编程和函数式编程
- 核心特性:C++增加了类、继承、多态、封装、模板、异常处理、命名空间等
- 内存管理:C用malloc/free,C++用new/delete,并支持构造/析构函数自动管理资源
- 类型检查:C++的类型检查更严格
- 标准库:C++有STL容器、算法和迭代器,功能更强大
2. 引用(Reference)与指针(Pointer)有什么区别?
- 初始化:引用必须在定义时初始化,指针可以先声明后赋值
- 重新绑定:引用一旦绑定不能改变,指针可以指向不同对象
- 空值:引用不能为空,指针可以是nullptr
- 语法:引用使用更简洁,像操作原变量一样;指针需要解引用操作
- 内存:引用通常不占额外空间(编译器优化),指针占用内存存储地址
- 使用场景:引用常用于函数参数传递,指针更灵活,适合动态内存和数据结构
3. 深拷贝与浅拷贝有什么区别?
- 浅拷贝:只复制对象的值,如果有指针成员,只复制指针地址,不复制指针指向的内容。多个对象共享同一块内存,析构时会导致重复释放
- 深拷贝:不仅复制对象的值,还会为指针成员重新分配内存并复制内容。每个对象独立管理自己的资源
- 默认行为:编译器生成的默认拷贝构造函数和赋值运算符执行浅拷贝
- 何时需要深拷贝:当类中有指针成员、动态分配的资源时,需要自定义深拷贝
4. 什么是构造函数和析构函数?
- 构造函数:对象创建时自动调用,用于初始化对象。函数名与类名相同,无返回值。可以重载,支持默认参数和初始化列表
- 析构函数:对象销毁时自动调用,用于清理资源(释放内存、关闭文件等)。函数名是~加类名,无参数无返回值,不能重载
- 调用时机:栈对象离开作用域时、delete堆对象时、程序结束时全局对象销毁
- 虚析构函数:基类析构函数应该是虚函数,确保通过基类指针删除派生类对象时正确调用析构函数
5. 如何定义常量(const)?
- 常量变量:
const int MAX = 100;必须初始化,不能修改 - 常量指针:
const int* p指向常量,不能通过p修改值;int* const p指针本身是常量,不能改变指向 - 常量引用:
const int& ref = value;常用于函数参数,避免拷贝且防止修改 - 常量成员函数:
void func() const;承诺不修改成员变量,可被常量对象调用 - 编译期常量:
constexpr int SIZE = 10;C++11引入,编译时求值
6. new 和 delete 是如何工作的?
- new的工作:①分配内存(调用operator new)②调用构造函数初始化对象③返回指向对象的指针
- delete的工作:①调用析构函数②释放内存(调用operator delete)
- 数组形式:
new[]分配数组,delete[]释放数组,必须配对使用 - 失败处理:new失败抛出bad_alloc异常,可用nothrow版本返回nullptr
- 与malloc/free区别:new/delete会调用构造/析构函数,malloc/free只管理内存
7. sizeof 和 alignof 的作用是什么?
- sizeof:编译期运算符,返回类型或对象占用的字节数。对数组返回总大小,对指针返回指针本身大小(通常4或8字节)
- alignof:C++11引入,返回类型的对齐要求(字节数)。CPU访问对齐的数据更高效
- 结构体大小:受内存对齐影响,可能有填充字节,不是简单的成员大小相加
- 使用场景:sizeof常用于内存分配、数组元素计数;alignof用于底层内存布局优化
8. 默认构造函数和拷贝构造函数有什么区别?
- 默认构造函数:无参数或所有参数都有默认值,用于创建对象。
MyClass obj;如果没定义任何构造函数,编译器会生成 - 拷贝构造函数:参数是同类型对象的引用,用于用已有对象初始化新对象。
MyClass obj2(obj1);或MyClass obj2 = obj1; - 调用时机:拷贝构造在对象作为函数参数传递、函数返回对象、用对象初始化另一对象时调用
- 编译器生成:如果不定义,编译器会生成默认版本,执行成员逐个拷贝
9. const 关键字的用途是什么?
- 定义常量:防止变量被修改,提高代码安全性
- 函数参数:
void func(const string& str)避免拷贝开销且保证不修改实参 - 成员函数:
int getValue() const表明不修改对象状态,常量对象只能调用const成员函数 - 返回值:
const int* getPtr()防止返回值被修改 - 编译优化:编译器可以对const进行优化,提高性能
- 接口设计:明确表达设计意图,增强代码可读性和可维护性
10. 如何使用 static 关键字?
- 静态局部变量:函数内的static变量只初始化一次,生命周期是整个程序,但作用域仅在函数内
- 静态全局变量/函数:限制作用域在当前文件,实现文件级封装,避免命名冲突
- 静态成员变量:属于类而非对象,所有对象共享,必须在类外初始化
- 静态成员函数:不依赖具体对象,只能访问静态成员,通过类名调用
- 使用场景:单例模式、计数器、工厂方法、工具函数等
查看20道真题和解析