ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

C 与 C++ 深度对比:不是“C + 类”这么简单

C 与 C++ 深度对比:不是“C + 类”这么简单 一、先定调关系与边界C 是 1972 年前后诞生的过程式系统语言C 是 1980 年代由 Bjarne Stroustrup 在 C 之上扩展出来的多范式语言。常见说法“C 是 C 的超集”只对一半大多数写得好的 C89 代码可以当作 C 编译但 C 不是 C 的数学子集有些 C 合法代码在 C 里非法C 也不是 C99/C11/C2x 的超集C 的 VLA、restrict、原生复数等 C 并不全盘接收。Stroustrup 自己的表述更准确C 支持 C 支持的每一种编程技术并且用更强的类型检查、更多记法支持来做。C 是“更好的 C”但不是 C 的纯超集。所以本质区别不是“多了几个关键字”而是C 把复杂度留在程序员脑子里C 把复杂度收进语言与标准库里。二、编程范式过程式 vs 多范式C过程式数据 函数组织单位是.c / .h、函数、struct、宏设计思路“先做什么、后做什么”C过程式 面向对象 泛型 一定程度函数式组织单位可以是类、模板、命名空间、模块C20设计思路可以是“怎么建模问题域”“怎么在编译期消除重复”“怎么让资源生命周期自动正确”一句话C 适合写“机器要做什么”C 适合写“系统是什么以及它如何被安全地构造和销毁”。三、类型系统宽松直接 vs 严格抽象这是工程上最容易被低估的一点。C 的类型哲学void*可以隐式转成任意指针函数未声明也能调用老式 C很多转换靠程序员自觉灵活但错误常拖到运行时C 的类型哲学void* - T*必须显式转换函数重载、模板、引用让“同样名字不同类型”变得安全const、访问控制、nullptr、强类型枚举提高静态检查能力模板在编译期做类型推导和约束C20 Concepts 更进一步例子// C void* p malloc(10 * sizeof(int)); int* q p; // 合法// C void* p ::operator new(10 * sizeof(int)); int* q p; // 编译错误 int* q2 static_castint*(p); // 必须显式说明意图C 不是“更啰嗦”而是把隐式假设变成显式契约。四、面向对象C 用手写约定C 用语言机制C 也可以用 struct 函数指针模拟对象typedef struct Animal { void (*speak)(struct Animal*); } Animal;但问题在哪没有访问控制struct字段谁都能改没有构造/析构初始化靠约定没有继承体系多态靠手填函数指针没有this语义统一API 容易乱C 把它变成语言级能力class Animal { public: virtual ~Animal() default; virtual void speak() 0; };差异不在“能不能写对象”而在维度CC封装注释级 / 约定级public/private/protected构造手写 init 函数构造函数销毁手写 cleanup析构函数继承手动嵌套 structclass Derived : public Base多态函数指针表virtual函数抽象成本显式、可控有虚表等成本但可预测C 的 OOP 不是装饰品它是大型系统里“接口稳定、实现可替换”的基础设施。五、内存与资源管理手动释放 vs RAII这是现代 C 最值钱的部分。C 模型int* arr malloc(n * sizeof(int)); if (!arr) { /* 处理分配失败 */ } // ... free(arr);人必须记得每条路径都freegoto cleanup/return前不能漏错误码返回时资源不能泄漏C 模型auto arr std::make_uniqueint[](n);或者std::vectorint v(n);资源在对象生命周期结束时自动释放这就是RAIIResource Acquisition Is Initialization资源获取即初始化析构即释放。包括内存unique_ptr / shared_ptr / vector文件fstream锁lock_guard / unique_lock套接字、句柄、事务都可以包装成对象结果C 的错误模式是“忘了 free”C 的错误模式是“对象所有权设计错了”后者比前者好调试得多。注意C 仍然可以手写new/delete但现代 C 的共识是——不要手动new/delete让对象管资源。六、泛型编程宏和 void* vs 模板C 的“通用代码”通常是void sort(void* base, size_t nmemb, size_t size, int (*cmp)(const void*, const void*));问题类型信息丢失比较函数通过函数指针调用难内联错误在运行时才暴露C 的模板templatetypename T void sort(T* first, T* last);优势类型安全编译器为每个类型生成专用代码比较器可以是 lambda / functor常被内联衍生出 STL、Eigen、Abseil、Boost 这类库C 的泛型不是“少写几行”而是把运行期多态变成编译期特化兼顾抽象与性能。七、标准库小内核 vs 大工业库C 标准库stdio.h、stdlib.h、string.h、math.h字符串是char*没有容器、没有算法库、没有线程多线程靠 pthread / platform APIC 标准库容器vector / map / unordered_map / set算法sort / find / transform / reduce字符串std::string并发std::thread / mutex / atomic / futureI/Oiostream、文件流C17 起std::filesystemC20 起ranges、concepts、modules、coroutines所以 C 项目常看到自研链表、哈希表、缓冲池、日志库、线程池C 项目常看到业务代码直接用 STL把精力放在领域模型上这也是为什么C 写“组件”C 写“系统”。八、错误处理错误码 vs 异常 不变式CFILE* f fopen(a.txt, r); if (!f) { perror(open); return -1; }特点错误码贯穿所有调用层业务逻辑和错误处理混杂忘了检查返回值就埋雷Ctry { do_something(); } catch (const std::runtime_error e) { log(e.what()); }但注意现代 C 不是到处抛异常底层库、游戏引擎、交易系统常禁异常高层业务可用异常很多场景用std::expectedC23 起更正式、错误码 强类型返回C 的真正进步是错误不再是“约定”而是类型/控制流的一部分。九、名字与接口组织全局平面 vs 命名空间/模块C 没有命名空间大型 C 项目靠前缀redis_free http_parse json_object_getC 有namespace net { class Socket; }C20 还有 modules解决头文件宏污染、重复解析、编译慢的问题。这对大团队很关键C 的接口边界靠文件名和前缀C 的接口边界可以靠命名空间、类、模板、模块十、兼容性与坑哪些 C 不是 C典型不兼容点void* p; int* q p;—— C 合法C 非法函数隐式声明 —— C 老代码常见C 不允许sizeof(a)—— C 里是sizeof(int)C 里是sizeof(char)C 关键字更多class、virtual、new、template、namespace不能作为变量名C 支持 VLAC99部分实现C 不支持C 有restrictC 没有标准等价物C 的结构体标签和类型名空间分离C 里struct Foo和Foo更接近同一类型名所以“把.c改成.cpp就能用”在玩具程序里成立在老项目里常翻车。十一、性能C 更快吗结论先给同水平程序员、同算法、同优化等级下C 和 C 性能基本同级。C 的抽象可以做到“零成本抽象”。std::vector不等于慢虚函数有成本但是可预测模板常常比void* 函数指针更快因为可内联异常在部分平台有体积/分支成本所以高频交易/游戏内核会禁用C 真正的性能陷阱是无脑继承、深拷贝、过度包装、模板递归爆炸C 的性能优势主要来自语言小运行时几乎为零没有异常、RTTI、虚表等“可选负担”C 的性能优势来自内联、特化、move 语义编译期计算更高层抽象但不牺牲机器效率所以不是“C 快C 慢”而是C 的开销你看得见C 的开销你得懂它才看得见。十二、适用场景别用锤子拧螺丝用 C 更合适操作系统内核、Bootloader驱动、裸机嵌入式、MCU跨语言 ABI 接口层C 是事实标准极端资源受限环境需要最小编译器依赖、最大可移植性的场景用 C 更合适游戏引擎浏览器内核数据库引擎高频交易图形图像、音视频管线大型后台服务需要容器/算法/并发/长期维护的系统经验法则越靠近硬件、越怕运行时依赖 → 选 C越靠近复杂业务、越怕人工管资源 → 选 C十三、学习路径先 C 还是先 C如果你目标是“真正懂系统”先学 C指针、栈/堆、结构体、内存布局、ABI、调用约定再学 C类、构造/析构、引用、重载、模板、RAII、STL最后学现代 C智能指针、move、lambda、concepts、ranges如果你目标是“做应用/游戏/工程”可以直接学现代 C但别只学语法要学所有权与生命周期最差的路线是用 C 的思维方式写 Cnew满天飞、裸指针传参、手动delete或者用 C 的复杂特性写 C硬上虚函数、模板、异常却跑在 8KB RAM 的 MCU 上十四、一句话总结C 是一门让你理解机器的语言C 是一门让你在理解机器之后管理复杂系统的语言。C 的哲学信任程序员给最小抽象C 的哲学在几乎不损失性能的前提下把复杂性关进类型系统和标准库所以C C 的底层能力 OOP 泛型 RAII STL 更强的静态约束但不是“C 加上 class”这么肤浅。
返回列表