解释下C与C++的区别?
C++是C语言的继承与发展,兼容C的语法,但引入了面向对象编程(OOP)范式。
从面向过程到面向对象的核心转变,使得C++在代码复用性、安全性和工程化能力上显著提升。具体如下:
一、面向对象特性
1. 封装性:
C语言(无封装):
- 结构体(
struct)仅作为数据容器,成员完全公开。 - 数据操作依赖外部函数,易导致数据被误修改。
C++(强封装): - 通过
class或struct将数据与操作封装为对象。 - 访问控制:
private隐藏内部细节,public暴露接口。 - 构造函数/析构函数:确保对象初始化和资源释放。
2. 继承性:代码复用与层次化设计
C语言(无原生继承):通过结构体嵌套模拟继承,但无语法支持。
C++(语法级继承):
C语言(手动模拟多态):通过函数指针实现多态,代码复杂且易出错。
C++(原生多态支持):
- 虚函数(
virtual):通过虚函数表(vtable)实现动态绑定。 - 纯虚函数:定义接口规范(类似Java的
interface)。
二、内存管理范式
new/delete vs malloc/free
- 对象生命周期管理:
new:分配内存 + 调用构造函数(对象初始化)。delete:释放内存 + 调用析构函数(资源清理)。
- RAII机制:通过对象作用域自动管理资源(如文件句柄、锁)。
而malloc和free管理的是动态分配的内存,而与对象的作用域无关。当你使用malloc分配内存时,这块内存将在堆(heap)中分配,这意味着它的生命周期独立于任何特定作用域。
三、编译与链接机制
函数名修饰(Name Mangling)
- C:函数名保持不变(如func → func),不支持重载。
- C++:函数名 + 参数类型编码到符号表(如func(int) → _Z4funci),支持重载。
- 影响:C++需用extern "C"禁用修饰以兼容C库。
四、变量初始化规则
静态变量初始化时机
- C:全局/静态变量在程序启动前初始化(编译期完成,仅支持基本类型)。
- C++:
- 局部静态变量:首次使用时初始化(线程安全,C++11起)。
- 支持复杂对象的构造(如调用类的构造函数)。
--------------------------------------------------------------------------------
说说C++的struct与class以及C的struct区别
- 默认访问:
struct成员和继承默认public,class默认private。 - 模板参数:模板中只能用
class或typename,不能用struct。
template <class T> // 合法
class Container {};
template <struct T> // 非法!
class AnotherContainer {};
- C的
struct:仅数据集合,无函数、访问控制或继承。
此外,C++11允许成员变量默认初始化,
而C不可在声明时初始化成员,需在实例化时或之后赋值。
C声明变量需带struct关键字,或对结构体使用typedef取别名,C++可省略
struct Point { int x, y; };
struct Point p = {1, 2};
struct Point p1; // 合法
typedef struct Point Point;
Point p2; // 合法(需typedef)
struct Point {
int x = 0; // C++11允许
int y = 0;
};
Point p; // 合法
总结对比表
| 特性 | C的struct | C++的struct | C++的class |
|---|---|---|---|
| 成员函数 | 不支持 | 支持 | 支持 |
| 访问控制 | 默认公有 | 默认公有 | 默认私有 |
| 继承默认权限 | 无继承 | 默认public继承 | 默认private继承 |
| 模板参数 | 不适用 | 不可用 | 可用(与typename等价) |
| 成员默认初始化 | 不支持(C11前) | 支持(C++11起) | 支持(C++11起) |
| 变量声明方式 | 需struct关键字或typedef | 直接使用类型名 | 直接使用类型名 |
--------------------------------------------------------------------------------
说说new和malloc的区别,各自底层实现原理
| 特性 | new | malloc |
|---|---|---|
| 语言 | C++操作符 | C标准库函数 |
| 重载 | 支持重载(operator new) | 不可重载 |
| 内存分配 | 自动计算所需内存大小 | 需手动指定字节数 |
| 类型安全 | 返回类型安全指针(无需强转) | 返回void*(需强转) |
| 错误处理 | 默认抛出std::bad_alloc异常 | 返回NULL |
| 构造/析构 | 调用构造函数和析构函数 | 仅分配/释放内存 |
| 内存来源 | 自由存储区(可能位于堆或静态存储区) | 堆(Heap) |
- 功能:
new是C++操作符,分配内存并调用构造函数;
malloc是C库函数,仅分配内存。new可以被重载,malloc不行。 - 类型安全:
new返回类型指针,malloc返回void*需强转。 - 错误处理:
new默认抛异常,malloc返回NULL。 - 底层实现上:
malloc通过brk/mmap管理堆内存,使用隐式链表减少碎片;
new通常调用malloc分配内存,再调用构造函数初始化对象。
malloc的实现- 内存分配策略:
- 小块内存(<128KB):通过
brk()系统调用调整堆顶指针(break),扩大堆空间。 - 大块内存(≥128KB):通过
mmap()直接在内存映射区分配匿名内存页。
- 小块内存(<128KB):通过
- 内存池管理:
- 隐式空闲链表:通过内存块头部信息(如块大小、是否空闲)串联所有内存块。
- 分割与合并:分配时分割空闲块,释放时合并相邻空闲块以减少碎片。
- 性能优化:
- 缓存机制:维护多个内存池(如
fastbins)加速小块内存分配。
new的实现
内存分配:
- 缓存机制:维护多个内存池(如
- 调用
operator new:底层通常调用malloc,但可重载以实现自定义分配策略。
对象构造:void* operator new(size_t size) { return malloc(size); // 默认实现 }- 分配内存后,编译器插入代码调用构造函数。
异常处理:MyClass* obj = new MyClass(); // 等价于: void* mem = operator new(sizeof(MyClass)); // 分配内存 MyClass* obj = static_cast<MyClass*>(mem); obj->MyClass(); // 调用构造函数- 默认抛出
std::bad_alloc异常,但可通过new (nothrow)禁用异常。
MyClass* obj = new (nothrow) MyClass(); // 失败返回nullptr - 内存分配策略:
--------------------------------------------------------------------------------
简述C/C++从源码到执行文件的整体流程
从源码到执行文件的整体流程上,C 和 C++ 的编译过程基本一致,都遵循 预处理 → 编译 → 汇编 → 链接 四个核心阶段,但在具体细节实现上存在差异。
1. 预处理(Preprocessing)
- 共同点:
- 处理
#include、#define、#ifdef等预编译指令。 - 删除注释,展开宏,生成 预处理后的代码(
.i或.ii文件)。
- 处理
- 差异:
C++ 预处理阶段可能处理更复杂的模板和命名空间等语法结构。
2. 编译(Compilation)
- C/C++ 共同点:
- 将预处理后的代码转换为 汇编代码(
.s文件)。 - 检查语法、类型、语义错误。
- 将预处理后的代码转换为 汇编代码(
- 差异:
- C++ 编译器(如
g++)默认启用名称修饰(Name Mangling),而 C 编译器(如gcc)不会。
- C++ 编译器(如
3. 汇编(Assembly)
- 完全一致:
- 将汇编代码转换为机器码,生成 目标文件(
.o或.obj文件)。
- 将汇编代码转换为机器码,生成 目标文件(
4. 链接(Linking)
- 共同点:
- 合并多个目标文件和库,解析符号引用,生成最终 可执行文件(如
.exe或.out)。
- 合并多个目标文件和库,解析符号引用,生成最终 可执行文件(如
- 差异:
- C++ 需要链接标准库(如
libstdc++或libc++),而C仅需libc。 - C++ 的名称修饰可能导致符号不兼容,混合 C/C++ 代码时需用
extern "C"声明。
- C++ 需要链接标准库(如
C与C++面试题解析
1万+

被折叠的 条评论
为什么被折叠?



