【笔记】C++的泛型编程

前言

C++的泛型编程学习笔记

函数模板

定义函数模版

  • 定义一个通用的数据类型
  • 函数模版可以用typename,类模板可以用class,也可以混用

T:通用的数据类型,通常为大写字母,通常命名为T

1
template<typename T>
1
template<class T>
  • 先定义模版,然后紧跟着定义函数,组成的就是函数模版的定义
1
2
3
4
5
6
7
template<typename T>
T func(T &t)
{
...

return t;
}

调用函数模板

自动类型推倒

  • 自动类型推倒要求当传递多个参数时,必须是一致的数据类型
  • 不会发生隐式类型转换
1
2
3
4
5
6
7
template<typename T>
void func(T t1, T t2)
{
...
}

func(1, 1);

显示指定类型

  • 如果函数没有使用到自定义类型,那么只能使用显示制定类型的方式调用函数模版
  • 显示类型需要写在<>
  • 会发生隐式类型转换
1
2
3
4
5
6
7
template<typename T>
void func()
{
...
}

func<int>();

普通函数和函数模板

  • 当普通函数和函数模版同时存在时,优先调用普通函数
  • 如果要强制调用函数模版,可以使用<>实现空模版参数列表的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
void func()
{
...
}

template<typename T>
void func()
{
// 此时这里的代码会被调用
...
}

func<>();

函数模板的重载

  • 利用具体化的类型实现重载方法,可以优先被调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Persion
{
public:
Persion() {}
}

template<typename T>
void func(T t)
{
...
}

template<> void func(Persion num)
{
// 此时这里的代码会被调用
...
}

Persion p();
func(p);

类模版

定义类模版

  • 定义一个通用的数据类型
  • 函数模版可以用typename,类模板可以用class,也可以混用

T:通用的数据类型,通常为大写字母,通常命名为T

1
template<typename T>
1
template<class T>
  • 先定义模版,然后紧跟着定义类,组成的就是类模版的定义
1
2
3
4
5
6
7
8
9
template<class T>
class Persion
{
private:
T id;
public:
Persion(T id);
this->id = id;
};

调用类模版创建对象

  • 类模版没有自动类型推导
  • 类模版的成员函数,不是一开始就调用,而是在创建时才去创建对象
1
Persion<int> id(1);

类模版的默认值

  • 类模版的模版参数列表可以有默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
template<class T>
class Persion
{
private:
T id;
public:
Persion(T id = int)
{
this->id = id;
}
};

Persion<> id(1);

类模版中成员函数的调用时机

  • 类模版中成员函数并不是编译的时候创建的,而是在调用时才去创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Persion1
{
public:
void method1() {}
};

class Persion2
{
public:
void method2() {}
};

template<class T>
class Persion
{
private:
T obj;
public:
void method1() {
obj.method1();
}

void method2() {
obj.method2();
}
};

void main()
{
Persion<Persion1> p1;
p1.method1();

Persion<Persion2> p2;
p2.method2();
}

类模版对象作为函数的参数

  • 先定义一个类模版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<class T>
class Persion
{
private:
T t;
public:
Persion(T t)
{
this->t = t;
}
void method()
{
...
}
};

指定传入类型

1
2
3
4
5
6
7
8
9
10
void method(Persion<int> &p)
{
p.method();
}

void main()
{
Persion<int>p(1);
method(p);
}

参数模版化

  • 相当于类模版与函数模版组合使用
1
2
3
4
5
6
7
8
9
10
11
template<class T>
void method(Persion<T> &p)
{
p.method();
}

void main()
{
Persion<int>p(1);
method(p);
}

将整个类模版化

  • 相当于类模版与函数模版组合使用
1
2
3
4
5
6
7
8
9
10
11
template<class T>
void method(T &p)
{
p.method();
}

void main()
{
Persion<int>p(1);
method(p);
}

类模版与继承

子类直接指定父类模版的类型

1
2
3
4
5
6
7
8
9
10
template<class T>
class Father
{
T t;
};

class Son:public Father<int>
{
...
};

子类也变为模版

子类指定父类的模版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<class T>
class Father
{
T t;
};

template<class T>
class Son:public Father<T>
{
T t;
};

void main()
{
Son<int> s;
}

子类同时指定父类模版和子类的模版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<class T>
class Father
{
T t;
};

template<class T_father, class T_son>
class Son:public Father<T_father>
{
T_son t_son;
};

void main()
{
Son<int, int> s;
}

类模版成员函数类外实现

类模版构造函数的类外实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<class T>
class Persion
{
private:
T t;
public:
Persion(T t);
};

template<class T>
Persion<T>::Persion(T t)
{
this->t = t;
}

类模版普通函数的类外实现

1
2
3
4
5
6
7
8
9
10
11
12
13
template<class T>
class Persion
{
private:
T t;
public:
void method();
};

void Persion<T>::method()
{
...
}

查看当前模版的数据类型

1
2
3
4
5
template<class T>
void method(T t)
{
typeid(T).name();
}

类模版的分文件编写

第一种方法

  • 主函数引入源文件
Persion.h
1
2
3
4
5
6
7
8
9
10
11
12
#pragma once
#include <iostream>
using namespace std;

template<class T>
class Persion
{
private:
T t;
public:
Persion(T t);
};
Persion.cpp
1
2
3
4
5
6
7
#include "Persion.h"

template<class T>
Persion<T>::Persion(T t)
{
this->t = t;
}
main.cpp
1
2
3
4
5
6
#include "Persion.cpp"

void main()
{
Persion<int> p(1);
}

第二种方法

  • 主函数引入模版头文件
Persion.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once
#include <iostream>
using namespace std;

template<class T>
class Persion
{
private:
T t;
public:
Persion(T t);
};

template<class T>
Persion<T>::Persion(T t)
{
this->t = t;
}
main.cpp
1
2
3
4
5
6
#include "Persion.hpp"

void main()
{
Persion<int> p(1);
}

类模版与友元

全局函数类内实现

1
2
3
4
5
6
7
8
template<class T>
class Persion
{
friend void method(Persion<T> p)
{
...
}
};

全局函数类外实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 声明类
template<class T>
class Persion;

// 实现全局函数
template<class T>
void method(Persion<T> p)
{
...
}

template<class T>
class Persion
{
// 声明全局函数
friend void method<>(Persion<T> p);
};

完成

参考文献

哔哩哔哩——黑马程序员