C++——类模板的概念和意义

1.一些类主要用于存储和组织数据元素,类中数据组织的方式和数据元素的具体类型无关,只关注需要实现的功能,如数组类、链表类、Stack类、Queue类

2.类模板的应用

(1)只能显示指定具体类型,无法自动推导

(2)使用具体类型<Type>定义对象

3.编译器对类模板的处理方式和函数模板相同

(1)从类模板通过具体类型产生不同的类

(2)在声明的地方对类模板代码本身进行编译

(3)在使用的地方对参数替换后的代码进行编译

复制代码
#include <iostream>
#include<string>
using namespace std;

template <typename T>
class Operator {
public:
	T add(T a, T b) {
		return a + b;
	}
	T minus(T a, T b) {
		return a - b;
	}
	T multiply(T a, T b) {
		return a * b;
	}
	T divide(T a, T b) {
		return a / b;
	}
};
int main() {
	Operator<int> op1;
	cout << op1.add(1, 2) << endl;
	Operator<string> op2;
	cout << op2.add("ab", "cd") << endl;
	// cout << op2.minus("ab", "cd") << endl; 报错,因为string类型没有减法运算
	return 0;
}

所以要重载string类型的减法运算符

复制代码
#include <iostream>
#include<string>
using namespace std;

template <typename T>
class Operator {
public:
	T add(T a, T b) {
		return a + b;
	}
	T minus(T a, T b) {
		return a - b;
	}
	T multiply(T a, T b) {
		return a * b;
	}
	T divide(T a, T b) {
		return a / b;
	}
};
string operator- (const string& a, const string& r) {
	return "Minus";
}
int main() {
	Operator<int> op1;
	cout << op1.add(1, 2) << endl; //3
	Operator<string> op2;
	cout << op2.add("ab", "cd") << endl; //abcd
	cout << op2.minus("ab", "cd") << endl; //Minus
	return 0;
}

4.类模板的工程应用

(1)类模板必须在头文件中定义

(2)类模板不能分开实现在不同的文件中

(3)类模板外部定义的成员函数需要加上模板<>声明

Complex.h

复制代码
#pragma once
//声明成员函数
template <typename T>
class Operator {
public:
	T add(T a, T b);
	T minus(T a, T b);
	T multiply(T a, T b);
	T divide(T a, T b);
};
//定义成员函数
template <typename T>
T Operator<T>::add(T a, T b) {
	return a + b;
}

template <typename T>
T Operator<T>::minus(T a, T b) {
	return a - b;
}

template <typename T>
T Operator<T>::multiply(T a, T b) {
	return a * b;
}

template <typename T>
T Operator<T>::divide(T a, T b) {
	return a / b;
}

main.cpp

复制代码
#include <iostream>
#include<string>
using namespace std;
#include "Complex.h"

int main() {
	Operator<int> op1;
	cout << op1.add(1, 2) << endl; //3
	cout << op1.minus(1, 2) << endl; //-1
	cout << op1.multiply(1, 2) << endl; //2
	cout << op1.divide(1, 2) << endl; //0
}

5.类模板可以定义任意多个不同的类型参数

类模板可以被特化:当通用类模板对某个 / 某些特定类型不适用、需要定制逻辑时,为这些类型单独编写专属的模板实现

(1)指定类模板的特定实现

(2)部分类型参数必须显示指定

(3)根据类型参数分开实现类模板

部分特化:用特定规则约束类型参数

完全特化:完全显示指定类型参数

部分特化:

复制代码
#include <iostream>
#include<string>
using namespace std;

template <typename T1, typename T2>
class Test {
public:
	void add(T1 a, T2 b) {
		cout << "void add(T1 a, T2 b)" << endl;
		cout << a + b << endl;
	}
};
template <typename T>
class Test<T, T> { //当Test类模板的两个类型参数完全相同时,使用这个实现
public:
	void add(T a, T b) {
		cout << "void add(T a, T b)" << endl;
		cout << a + b << endl;
	}
};
int main() {
	Test<int, float> t1;
	t1.add(1, 2.5);
	Test<long, long> t2;
	t2.add(5, 5);
	return 0;
}

运行结果:

void add(T1 a, T2 b)

3.5

void add(T a, T b)

10

完全特化:

  • 完全特化 表示显示指定类型参数 ,模板声明只需写成template<>,并在类名右侧指定参数

    #include <iostream>
    #include<string>
    using namespace std;

    template <typename T1, typename T2>
    class Test {
    public:
    void add(T1 a, T2 b) {
    cout << "void add(T1 a, T2 b)" << endl;
    cout << a + b << endl;
    }
    };
    template <typename T1,typename T2>
    class Test<T1*, T2*> {
    public:
    void add(T1* a, T2* b) {
    cout << "void add(T1 * a, T2 * b)" << endl;
    cout << *a + *b << endl;
    }
    };

    //完全特化
    template< >
    class Test<void*, void* > {
    public:
    void add(void* a, void* b) { //当T1==void* 并且 T2==void* 时
    cout << "void add(void* a, void* b)" << endl;
    cout << "Error..." << endl;
    }
    };
    int main() {
    Test<int, float> t1;
    t1.add(1, 2.5);

    复制代码
      Test<void*, void*> t3;
      t3.add(NULL, NULL);
    
      Test<int*, double*> t4;
      int a = 1;
      double b = 0.1;
      t4.add(&a, &b);
      return 0;

    }

运行结果:

void add(T1 a, T2 b)

3.5

void add(void* a, void* b)

Error...

void add(T1 * a, T2 * b)

1.1

6.类模板特化注意事项

(1)特化只是模板的分开实现,本质上是同一个类模板

(2)特化类模板的使用方式是统一的,必须显示指定每一个类型参数

类模板特化和重定义的区别?

重定义:一个类模板和一个新类,或者两个类模板;

特化:以统一的方式使用类模板和特化类,编译器自动优先选择特化类

函数模板也可以特化,但只能完全特化

复制代码
#include <iostream>
#include<string>
using namespace std;
////完全特化
//template< >
//class Test<void*, void* > {
//public:
//	void add(void* a, void* b) { //当T1==void* 并且 T2==void* 时
//		cout << "void add(void* a, void* b)" << endl;
//		cout << "Error..." << endl;
//	}
//};

//对上面的特化的重定义
class Test_Void {
public:
	void add(void* a, void* b) {
		cout << "void add(void* a, void* b)" << endl;
	}
};

//函数模板
template<typename T>
bool Equal(T a, T b) {
	cout << "bool Equal(T a, T b)" << endl;
	return a == b;
}
//函数模板的完全特化
template<>
bool Equal<double>(double a, double b) {
	const double delta = 0.00000000000001;
	double r = a - b;
	cout << "bool Equal<double>(double a, double b)" << endl;
	return (-delta < r) && (r < delta);
}
int main() {
	
	//Test<void*, void*> t3;
	Test_Void t3;
	t3.add(NULL, NULL);
	cout << Equal(1, 1) << endl;
	cout << Equal<double>(0.001, 0.001) << endl; //由于浮点数在内存中的表示是不精确的,所以不能用==比较,所以要用函数的完全特化
	return 0;
}

运行结果:

void add(void* a, void* b)

bool Equal(T a, T b)

1

bool Equal<double>(double a, double b)

1

相关推荐
xiaoye-duck2 小时前
《算法题讲解指南:递归,搜索与回溯算法--二叉树中的深搜》--8.二叉树剪枝,9.验证二叉搜索树
c++·算法·深度优先·递归
承渊政道2 小时前
C++学习之旅【异常相关内容以及类型转换介绍】
c语言·c++·笔记·vscode·学习·macos·visual studio
liulilittle2 小时前
Debian/Ubuntu 18.04 上安装 GLIBC 2.28 (2026)
linux·运维·服务器·开发语言·c++·ubuntu·debian
承渊政道2 小时前
C++学习之旅【深入回溯C++11的发展历程】
c语言·c++·笔记·vscode·学习·macos·visual studio
xiaoye-duck11 小时前
《算法题讲解指南:递归,搜索与回溯算法--递归》--3.反转链表,4.两两交换链表中的节点,5.快速幂
数据结构·c++·算法·递归
山栀shanzhi11 小时前
归并排序(Merge Sort)原理与实现
数据结构·c++·算法·排序算法
Trouvaille ~11 小时前
【递归、搜索与回溯】专题(七):FloodFill 算法——勇往直前的洪水灌溉
c++·算法·leetcode·青少年编程·面试·蓝桥杯·递归搜索回溯
zhooyu12 小时前
二维坐标转三维坐标的实现原理
c++·3d·opengl
10Eugene12 小时前
C++/Qt自制八股文
java·开发语言·c++