加载中...
Hello STL - 向量篇1 - 范式对比&特性彰显
第1节:初学C++,应该学什么?
第2节:《白话C++》练的什么“功”?
第3节:《白话C++》练的什么“武”?
第4节:打开浏览器,线上玩转C++
第5节:逐字逐句,深入理解C++最小例程
第6节:做一个“会”犯错误的程序员
第7节:Hello World 中文版
第8节:Hello World 函数版
第9节:Hello World 交互版
第10节:Hello World 分支版
第11节:Hello World 循环版
第12节:Hello Object 生死版.上
第13节:Hello Object 生死版. 下
第14节:Hello Object 成员版
第15节:Hello Object 派生版
第16节:Hello Object 多态版
第17节:Hello Object 封装版 - 上
第18节:Hello Object 封装版 - 下
第19节:Hello STL - 泛型启蒙
第20节:Hello STL - 向量篇1 - 范式对比&特性彰显
课文封面

孙悟空在鸡精窝前叫骂,
鸡精们选择了忍耐,
孙悟空在象妖洞前叫骂,
象妖们选择了愤怒,
如何用简洁的代码来模拟?
看!函数模板和函数重载擦出了不一样的火花。

1. 函数重载 vs.函数模板

有没有同学想过,C++中的函数重载和函数模板,是一对互相反着来的好兄弟?

函数重载和函数模板

  • 函数重载:写多个函数,用起来却好像是一个函数
  • 函数模板:写一个函数,用起来却好像是多个函数

比如函数重载:

int AddTwo(int a, int b) { return a + b; } double AddTwo(double a, double b) { return a + b; }

用起来好像是一个函数:

auto r1 = AddTwo(100, 200); auto r2 = AddTwo(100.1, 200.2);

改用函数模板实现:

template <typename T> T AddTwo(T const& a, T const& b) { return a + b; }

用起来,仿佛有 N 个函数:

auto r3 = AddTwo(100, 200); auto r4 = AddTwo(100.1, 200.2); auto r5 = AddTwo<std::string>("abc", "123");

今天,我们就要上演一场“函数重载”和“函数模板”这对兄弟齐心协力,针对特定问题的实现完美设计的戏……

这出戏的起源,是来自上一节课末了的另外一对兄弟,一对毫无血缘关系的“兄弟”:

struct 鸡精 { void 忍耐 () {cout << "欢迎品尝!\n";} }; struct 象妖 { void 愤怒 () {cout << "大胆!可笑!\n";} };

尽管可以一眼看出,鸡精和象妖都不是好人,按理说它们应该有一个共同基类:“妖怪”;但,我是处于“愚者”状态的开发者,我就是没能在一开始时为它们加上这个共同基类,现在,甲方爸爸说:

我们这出戏演的是:有两个妖洞:鸡精窝和象妖洞,猴子一前一后跑到它们洞口叫骂:“里面的妖怪都给爷爷出来……” 请用一段 C++ 代码来模拟两个洞里的妖怪的此刻的不同反应……

就在我刚想写一个妖怪的接口,再为它加一个 “反应()” 的纯虚方法并分头在鸡精和象妖现有结构体上实现时,开发大厅某根柱子上贴着的乾隆墨宝:“对修改封闭,对扩展开放” 冷冷地看着我……

“领导,我想为现有的类添加基类和新方法,这样算修改吗?”

因为我已经50岁了……领导最近一直想给我穿小鞋,她叫到 “不管你往现有的结构体中塞入任何东西 ,都算修改!只能开除!”

“那我写派生类怎么算?”

“派生类?‘鸡精’ 这么具体的类,你还要怎么派生?派生类叫什么?叫‘遇到猴子会有反应的鸡精’吗? ”

遇到猴子会有反应的鸡精?听起来就不像是什么正经鸡精……我看了一眼领导,默默地翻起讲泛型编程的书。

2. 原理讲解 🎥

3. 项目演示 🎥

以下是演示项目的完整代码:

#include <iostream> #include <vector> using namespace std; struct 鸡精 { void 忍耐 () {cout << "欢迎品尝!\n";} }; struct 象妖 { void 愤怒 () {cout << "大胆!可笑!\n";} }; // 适配器,“垫片” - 反应 void 反应(鸡精& jj) { jj.忍耐(); } void 反应(象妖& xy) { xy.愤怒(); } // 叫阵函数模板 template <typename YokaiT> void 叫阵(char const* 洞名, std::vector<YokaiT> & cave) { std::cout << 洞名 << "里面的妖怪快出来见爷爷!\n"; for (auto & yokai : cave) { 反应(yokai); } } int main() { vector<鸡精> cave1; cave1.push_back(鸡精{}); cave1.push_back(鸡精{}); cave1.push_back(鸡精{}); vector<象妖> cave2; cave2.push_back(象妖{}); cave2.push_back(象妖{}); 叫阵("鸡精窝", cave1); 叫阵("象妖洞", cave2); }