OOP与GP是C++中协同而非互斥的抽象机制:OOP聚焦“谁来做”,通过类、继承、多态建模实体;GP聚焦“怎么做才通用”,借模板实现编译期类型无关复用。

面向对象编程(OOP)和泛型编程(GP)在C++中是两种不同维度的抽象机制,不是互斥的替代关系,而是常协同使用的思想工具。OOP关注“**谁来做**”——通过类、继承、多态建模现实或逻辑中的实体与行为;GP关注“**怎么做才通用**”——通过模板让算法和数据结构脱离具体类型,实现编译期的类型无关复用。
核心出发点不同:建模 vs 复用
OOP以“分类+封装+交互”为逻辑起点:把数据和操作打包成类,用继承表达共性与差异,靠虚函数实现运行时多态。比如Shape → Circle / Rectangle,调用draw()时行为由实际对象决定。
泛型编程以“抽象掉类型”为第一目标:不关心具体是int还是std::string,只关注类型是否支持所需操作(如+、==、迭代器解引用)。比如std::sort(first, last)对任意满足随机访问和可比较的类型都有效。
- OOP的灵活性主要在运行时(动态绑定),代价是虚函数调用开销和对象布局约束
- GP的灵活性在编译时(模板实例化),零运行时开销,但错误信息难读、编译时间长、接口隐含(靠文档或SFINAE约束)
抽象粒度与表达方式不同
OOP的抽象单位是**类/对象**,强调“状态+行为”的统一,适合描述具有明确身份、生命周期和交互协议的实体(如BankAccount、NetworkConnection)。
立即学习“C++免费学习笔记(深入)”;
GP的抽象单位是**模板+概念(C++20后)**,强调“操作契约”,例如std::ranges::range不规定内部怎么存,只要求能获得begin/end迭代器;std::invocable不关心是函数指针、lambda还是重载了operator()的类,只要可调用就行。
- 写OOP代码常思考:“这个功能该放在哪个类里?要不要虚函数?要不要向上转型?”
- 写GP代码常思考:“这个算法依赖哪些操作?哪些类型能提供这些操作?能不能用concept提前说清楚?”
组合使用才是C++的常态
真实项目中,二者极少单用。典型例子:
-
std::vector是泛型容器(模板类),但内部封装了内存管理、异常安全等OOP式职责 -
std::shared_ptr用模板参数化所指类型,却用引用计数对象(带构造/析构/拷贝控制)体现OOP思想 - GUI框架中,
Widget是基类(OOP),而Signal是泛型事件槽(GP)
选范式不是非此即彼,而是看问题本质:需要表达“is-a”或“has-a”关系?优先OOP;需要写一个和类型无关的算法或容器?优先GP;既要灵活接口又要清晰语义?两者一起上。
基本上就这些。理解区别是为了更自觉地选择工具,而不是背概念。C++的强大,正在于它不强迫你只用一种方式思考问题。










