C++模板(泛型编程)

在这里插入图片描述

✨Blog:🥰不会敲代码的小张:)🥰
🉑推荐专栏:C语言🤪Cpp😶‍🌫️数据结构💀
💽座右铭:“記住,每一天都是一個新的開始😁😁😁
💀本章内容:《C++模板》的介绍✨

模板介绍

C++中的模板是一种通用编程工具,允许编写泛型代码,以便在不同类型的数据上工作而不需要重复编写多个版本的代码。

C++中有两种主要类型的模板:
函数模板
类模板

日常使用classtypename没有区别。

函数模板

模板参数定义的是类型

template <typename  Tp>

函数模板:

template <typename  T>
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int a = 1;
	int b = 2;
	double c = 1.1;
	double d = 2.2;
	Swap(a, b);
	//Swap(c, d);
	return 0;
}

我们可以传任何类型给Swap函数,因为它已经不是普通的函数,如果我们不写模板,那么我们就需要指定类型。有了模板后,这些事情编译器就会替我们解决,如果需要int类型的,编译器会实例化int类型的,如果需要double类型,同样也会去实例化double类型…看似调用的是同一个函数,实则不同类型的调用,底层已经变了。
调用的不是同一个函数,函数模板实例化生成具体函数。
根据调用,自己推到模板参数类型,实例化出对应的函数。
在这里插入图片描述

有些函数无法自动推类型,只能显示实例化:
在这里插入图片描述

这种场景只能显示实例化:
在这里插入图片描述

类模板

模板实例化类的需求:
在这里插入图片描述

普通类:类名和类型是一样的

Stack s;

类模板:类名和类型不一样

类名:Stack
类型:Stack<T>

类只能显示实例化:
在这里插入图片描述

类模板实例化不同的模板参数就是不同的类型!!!!!!!!!

模板进阶

  1. 模板可以控制容器里面的数据问题
  2. 可以控制逻辑,比如说适配器

typename和class的区别

如果不再container前面加上typename那么编译器会分不清它到底是类型还是对象,加上typename的意思就是告诉编译器,这是个类型,具体什么类型还不知道,因为还没有实例化。需要继续让编译器往下去走回过头来才能确定类型,因为编译器是自顶向下编译的,在编译的时候还没走到具体类型,就遇到了不知道是对象还是类型的语句,所以加上typename是告诉编译器是类型。

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

template<class Container>
void Print(const Container& x)
{
	//typename Container::const_iterator cit = x.begin();
	Container::const_iterator cit = x.begin();//报错
	while (cit != x.end())
	{
		cout << *cit << " ";
		++cit;
	}
	cout << endl;
}

int main()
{
	string s;
	s = "hello world";
	Print(s);
	return 0;
}

总结:如果类模板要去类里面取东西,但类型还没有被实例化,就要使用typename

非类型模板参数

1.常量
2.必须是整形

假设我们想定义一个静态的栈,大小是100,然后又需要一个栈大小是10。下面这种情况我们只能写死,但是对于s2来说100太大了。

#define Size 100

template<class T>
class Stack
{
private:
	T _a[Size];
	int _top;
};

int main()
{
	//需要100的大小
	Stack<int> s1;
	//需要10的大小
	Stack<int> s2;
	return 0;
}

非类型模板参数就可以很好的解决这里的问题

template<class T, size_t N>
class Stack
{
private:
	T _a[N];
	int _top;
};

int main()
{
	//需要100的大小
	Stack<int, 100> s1;
	//需要10的大小
	Stack<int, 10> s2;
	return 0;
}

模板特化(特殊化处理)


// 通用的模板类 Array
template <typename T>
class Array {
public:
    void print() {
        std::cout << "Generic Array" << std::endl;
    }
};

// 针对 int 类型的特化
template <>//注意格式
class Array<int> {
public:
    void print() {
        std::cout << "Specialized Array for int" << std::endl;
    }
};

int main() {
    Array<double> arr1;
    Array<int> arr2;

    arr1.print(); // 输出: Generic Array
    arr2.print(); // 输出: Specialized Array for int

    return 0;
}

全特化:模板参数全部特殊化处理
全特化是对模板中所有的参数进行特化的情况。也就是说,所有的模板参数都被明确指定了。
它通常用于为特定组合的模板参数提供定制化的实现。
全特化的模板声明和定义都要提供,而不是使用通用模板。

// 通用模板类
template <typename T, typename U>
class MyClass 
{
public:
    void print() 
    {
        std::cout << "Generic MyClass" << std::endl;
    }
};

// 全特化为 int, double 类型
template <>
class MyClass<int, double> 
{
public:
    void print() 
    {
        std::cout << "Specialized MyClass for int, double" << std::endl;
    }
};
int main()
{
    MyClass<int, int> x1;
    MyClass<int, double> x2;
    x1.print();
    x2.print();

    return 0;
}

偏特化:特化部分参数/可能对某些类型进一步限制


// 通用模板类
template <typename T, typename U>
class MyClass 
{
public:
    void print() 
    {
        std::cout << "Generic MyClass" << std::endl;
    }
};
// 偏特化为 T 类型为 int 的情况
template <typename U>
class MyClass<int, U> 
{
public:
    void print() 
    {
        std::cout << "Partial Specialization for int" << std::endl;
    }
};

模板分离编译

Myclass.h文件

#include <iostream>
using namespace std;

template<class T>
class MyClass
{
public:
	void print();
};

Myclass.cpp文件

#include "stack.h"

template<class T>
void MyClass<T>::print()
{
	cout << "hello world" << endl;
}

test.cpp文件

int main()
{
    MyClass<int> m;
    m.print();
    
    return 0;
}

报错结果:
在这里插入图片描述
一般这种报错都是编译链接时候的错误,为什么呢?

涉及模板声明定义分离,在链接过程找不到定义地址,因为模板没有实例化,所以编译器不知道如何生成地址

解决方法:
显示实例化,但是这种方法治标不治本。打个比方来说,那我如果需要实例化double类型呢?char类型呢?难不成都要手动去实例化?
在这里插入图片描述
如果非要声明和定义分离,最好在同一个文件进行,这样就能有效的解决问题
在这里插入图片描述
总结:

优点:

  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库STL因此而产生。
  2. 增强了代码的灵活性。
    缺点:
  3. 模板会导致代码膨胀(类模板实例化不同的模板参数就是不同的类型,编译器会自己生成,只是我们看不见),也会导致编译时间变长。
  4. 出现模板编译报错时,错误信息凌乱,不容易定位错误。
  • 42
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会敲代码的小张:)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值