OOP Lec11: Template

Template

一个模板完全都是声明,应该只有 .h,而不含有 .cpp

当我们需要操作不同类型的,功能和实现类似的容器,往往就需要使用模板元编程。

其他的一些解决方案:

  1. 构造公共父类(Java 的 Object 类)
    • 可能无法实现(C++ 没有单根结构,有 Fully in 结构)
  2. 复制代码
    • 设计不良
  3. 无类型的容器
    • 类型检查非常差

概念

模板实际上是代码的重用。

  • 产生了泛型编程(generic programming)
  • 在定义中将类型作为参数

分为函数模板类模板。注意,模板不是类或者函数,它用于生成类或函数。

模板本身不会存在于编译后的代码中。

模板实例化指用模板和具体的类型生成具体的函数和类。

函数模板

模板声明

使用 template 关键字来声明模板,其中用 typenameclass声明类型参数,他们是等价的。

template<typename _Tp>
void swap(_Tp& x, _Tp& y){
    _Tp temp = x;
    x = y;
    y = temp;
}

模板实例化

#include <algorithm>
#include <iostream>

int add(int x, int y){
    return x + y;
}

template<typename _Tp>
_Tp add(_Tp x, _Tp y){
    return x + y;
}

signed main(int argc, char **argv){
    std::cout << add(1, 2) << std::endl; 
    std::cout << add(1.1, 2.2) << std::endl;
    return 0;
}

编译,使用 nm -CU a.out 指令,可以发现定义了两个函数
T add(int, int)T double add<double>(double, double)

一般情况下(全部

可以显式地实例化:add<double>(1.1, 2.2)。在函数参数不能推断出模板中所有参数时,请使用显式实例化。

参数匹配

可以发现,如果有原生的完全匹配的函数,优先使用原生函数,例如 add(1, 2) 调用 add(int, int)

其次,如果有模板能完全匹配的函数,使用模板生成函数,例如 add(1.1, 2.2) 调用 add<double>(dobule, double)

再其次,尝试使用类型转换来匹配其他原生函数。但是,类型转换不能用于匹配模板,例如 add(1, 2.2)

类模板

模板声明

template<typename T>
class Vector{
public:
    Vector(int s):size(s){
        content = new T[size];
    }
    virtual ~Vector(){
        delete[] content;
    }
    T& operator[](int p){
        return content[p];
    }
private:
    T* content;
    int size;
};

可以在模板参数中使用一些常量

template<typename T, int bounds = 100>
class Container{
public:    
private:
    int content[bounds];//ok
}
Container<int, 500> v1;
Container<int> v2;

这样的操作可以让代码稍微快一点(相比于动态内存分配),但会造成代码冗余(所有容器都需要指定长度、内部实现都要带参数),所以应当慎重使用。

模板实例化

Vector<int> vi(4);
Vector<std::string> vs(4);

可以嵌套实例化

std::vector<std::vector<int>> array;
std::vector<int (*)(std::vector<double>&, int)> funcptr;

继承

template<typename T>
class Derived: public Base;

template<typename T>
class Derived: public List<T>;

class Group: public List<Employee*>;

模板可以从实例类继承,可以从类模板继承。

实例类只能从实例类继承。

备注

总的来说,模板的内容应该全部放在头文件中,不能用单独的 .cpp 文件来保存实现。

这是因为,模板并不是函数或类,全部都是声明,编译后只有实例化的函数和类会留在 .obj 中。

静态变量

对于同一个模板类的静态变量,应该在 .h 中声明其位置:

template<typename T>
int Derived<T>::size = 10;

这样实际调用时,会为每个不同的 T 生成一个 size 变量。

使用建议

在编写一个模板时,可以注意以下要点:

  1. 先编写一个非模板的版本(实例)
  2. 准备一些测试数据,准备用于测试效率和正确性
  3. 通过观察,确定需要作为参数的类型
  4. 将类型转换为类型参数,并使用数据测试
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇