掌 握 模 板 与 内 存 管 理,你 就 是 下 一 个 C++ 编 程 大 神!代 码 冗 余?内 存 泄 漏?不 存 在 的!
本文讲解 C++模板,包括函数模板和类模板,介绍其定义、用法及实例化。
掌 握 模 板 与 内 存 管 理,你 就 是 下 一 个 C++ 编 程 大 神!代 码 冗 余?内 存 泄 漏?不 存 在 的!
💻作 者 简 介:曾 与 你 一 样 迷 茫,现 以 经 验 助 你 入 门 C++。
💡个 人 主 页:@笑口常开xpr 的 个 人 主 页
📚系 列 专 栏:C++ 炼 魂 场:从 青 铜 到 王 者 的 进 阶 之 路
✨代 码 趣 语:swap 模 板 藏 着 偷 懒 的 智 慧:与 其 给 每 个 类 型 写 交 换 代 码,不 如 让 编 译 器 按 类 型 ‘ 抄 作 业 ’,抄 得 又 快 又 准。
💪代 码 千 行,始 于 坚 持,每 日 敲 码,进 阶 编 程 之 路。
📦gitee 链 接:gitee
在 C++ 的 编 程 世 界 里, 内 存 管 理 与 代 码 复 用 始 终 是 开 发 者 绕 不 开 的 核 心 话 题。今 天,我 们 聚 焦 于 C++ 模 板 这 一 强 大 工 具,它 宛 如 代 码 世 界 的 “ 万 能 模 具 ”,打 破 类 型 束 缚,让 同 一 份 逻 辑 能 适 配 多 样 数 据 类 型;同 时 也 会 结 合 new/delete 底 层,帮 你 贯 通 内 存 管 理 与 通 用 编 程 的 关 键 脉 络,一 起 解 锁 更 高 效 的 C++ 编 程 姿 势。
模 板
交 换 函 数
实 现 通 用 的 交 换 函 数
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
void Swap(double& left, double& right)
{
double temp = left;
left = right;
right = temp;
}
void Swap(char& left, char& right)
{
char temp = left;
left = right;
right = temp;
}
缺 点
- 重 载 的 函 数 仅 仅 是 类 型 不 同,代 码 复 用 率 比 较 低,只 要 有 新 类 型 出 现 时,就 需 要 用 户 自 己 增 加 对 应 的 函 数。
- 代 码 的 可 维 护 性 比 较 低,一 个 出 错 可 能 所 有 的 重 载 均 出 错
定 义
模 板 是 一 个 “代 码 蓝 图”,可 以 根 据 传 入 的 类 型 “生 成” 对 应 版 本 的 具 体 代 码。
核 心 价 值
解 决 “同 逻 辑、不 同 类 型” 的 代 码 冗 余 问 题。
分 类
函 数 模 板
定 义
定 义 一 个 通 用 函 数,参 数 类 型 通 过 模 板 参 数 指 定,编 译 器 会 根 据 传 入 的 实 参 类 型 自 动 生 成 对 应 版 本 的 函 数。
格 式
template<typename T>
使 用 template 和 typename 来 声 明 模 板,这 里 的 typename 也 可 以 使 用 class 来 代 替,不 可 以 使 用 struct。T 是 参 数 类 型,可 以 是 内 置 类 型 或 者 自 定 义 类 型,可 以 作 为 函 数 的 参 数 或 者 返 回 值。
多 个 类 型
template<typename T1,typename T2>
代 码 示 例
#include<iostream>
using namespace std;
template<typename T>//T是模板参数,类似于形参,定义的是类型
void Swap(T& x1, T& x2)
{
T tmp = x1;
x1 = x2;
x2 = tmp;
}
int main()
{
int a = 0;
int b = 1;
double c = 1.1, d = 2.2;
Swap(a, b);
cout << a << " " << b << endl;
Swap(c, d);
cout << c << " " << d << endl;
return 0;
}
上 面 的 代 码 中,2 个 Swap 调 用 的 不 是 同 一 个 函 数,编 译 器 通 过 类 型 自 动 推 导 出 函 数。
函 数 模 板 的 原 理
编 译 器 根 据 参 数 类 型 推 导 出 具 体 函 数。
可 以 直 接 使 用 库 里 面 的 swap 模 板,库 里 面 的 swap 是 小 写。
#include<iostream>
using namespace std;
int main()
{
int a = 1;
int b = 2;
cout << a << " " << b << endl;
swap(a, b);
cout << a << " " << b << endl;
return 0;
}
函 数 模 板 的 实 例 化
隐 式 实 例 化
编 译 器 根 据 实 参 推 演 模 板 参 数 的 实 际 类 型。
#include<iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.1, d2 = 20.2;
cout << Add(a1, d1) << endl;
return 0;
}
代 码 报 错 是 因 为 a1 和 d1 的 类 型 不 同,模 板 参 数 列 表 中 只 有 一 个 T,编 译 器 无 法 确 定 此 处 到 底 该 将 T 确 定 为 int 或 者 double 类 型 而 报 错,在 模 板 中,编 译 器 一 般 不 会 进 行 类 型 转 换 操 作。 下 面 有 两 种 解 决 方 法。
方 法 1
在 参 数 前 面 添 加 强 制 类 型 转 换。
#include<iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.1, d2 = 20.2;
cout << Add(a1, (int)d1) << endl;
cout << Add((double)a1, d1) << endl;
return 0;
}
不 同 的 强 制 类 型 转 换,得 到 的 结 果 是 不 一 样 的。
方 法 2
显 示 类 型 转 换,在 函 数 名 后 的 < > 中 指 定 模 板 参 数 的 实 际 类 型
#include<iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.1, d2 = 20.2;
//cout << Add(a1, a2) << endl;
//cout << Add(d1, d2) << endl;
//强制类型转换
//cout << Add(a1, (int)d1) << endl;
//cout << Add((double)a1, d1) << endl;
//显示实例化
cout << Add<int>(a1, d2) << endl;//隐式类型转换
cout << Add<double>(a1, d2) << endl;
return 0;
}
Add 函 数 中,使 用 const 是 因 为 隐 式 类 型 转 换 会 产 生 临 时 变 量,临 时 变 量 具 有 常 性。
特 殊 情 况
有 些 函 数 无 法 自 动 推 导,只 能 显 示 实 例 化。
#include<iostream>
using namespace std;
template<typename T>
T* Alloc(int n)
{
return new T[n];
}
int main()
{
double* p1 = Alloc<double>(10);
return 0;
}
泛 型 编 程
使 用 模 板 来 完 成 的,代 码 针 对 广 泛 的 类 型。
类 模 板
格 式
template<class T1, class T2, ..., class Tn>
class 类模板名
{
//类内成员定义
};
类 模 板 可 以 定 义 多 个 模 版 参 数。
代 码 示 例
类 模 板 只 能 显 示 实 例 化,不 能 传 递 参 数。
#include<iostream>
using namespace std;
template<typename T>
class Stack
{
public:
Stack(size_t capacity = 3)
{
cout << "StackInt(size_t capacity = 3)" << endl;
_array = new T[capacity];//只需要个数
_capacity = capacity;
_size = 0;
}
void Push(const T& data)
{
_array[_size] = data;
_size++;
}
~Stack()
{
cout << "~StackInt()" << endl;
if (_array)
{
free(_array);
_array = NULL;
_capacity = 0;
_size = 0;
}
}
private:
T* _array;
int _capacity;
int _size;
};
int main()
{
Stack<int> s1;//int
Stack<double> s1;//double
return 0;
}
类 模 板 的 实 例 化
类 模 板 实 例 化 与 函 数 模 板 实 例 化 不 同,类 模 板 实 例 化 需 要 在 类 模 板 名 字 后 跟 < >,然 后 将 实 例 化 的 类 型 放 在 < > 中 即 可,类 模 板 名 字 不 是 真 正 的 类,而 实 例 化 的 结 果 才 是 真 正 的 类。
普 通 类,类 名 和 类 型 一 样,类 模 板,类 名 和 类 型 不 一 样。例 如:类 名:Stack,类 型:Stack< T >。
template< typename T > 的 作 用 范 围 是 下 一 个 函 数 或 者 类。
总 结
模 板 的 出 现,让 C++ 代 码 摆 脱 了 重 复 冗 余 的 枷 锁,无 论 是 函 数 模 板 实 现 通 用 逻 辑 复 用,还 是 类 模 板 构 建 灵 活 数 据 结 构,都 极 大 提 升 了 编 程 效 率 与 代 码 可 维 护 性。掌 握 这 些 知 识,就 像 拿 到 了 C++ 进 阶 的 密 钥,助 力 我 们 写 出 更 简 洁、更 高 效、更 具 扩 展 性 的 代 码,在 编 程 之 路 上 走 得 更 远、更 稳,去 探 索 更 广 阔 的 代 码 天 地。
更多推荐
所有评论(0)