目录
一、C++类模板和函数模板
1.类模板
2.函数模板
二,Typescript 的泛型声明
1.泛型函数
2.泛型类
为什么C++和Typescript语言中主张模板和泛型
一、C++类模板和函数模板
在C++中,类模板和函数模板允许你为多种数据类型编写通用的代码。这就像每个人都有鼻子,耳朵,眼镜。但是有些人整合在一起就是帅哥美女,有的就长成。。。
C++主要分为两个模板-------类模板和函数模板。
1.类模板
template<class T1, class T2, class Tn>
class 类模板名
{
// 类内成员定义
};
通常类模板是这样的格式。(typename是用来定义模板参数关键字,也可以使用class。切记:不能使用struct代替class)
template <typename T>
class AnimalHouse {
private:
T size; // 房间的大小
public:
AnimalHouse(T size) : size(size) {} // 构造函数,用来设置房间的大小
void displaySize() {
std::cout << "房间的大小是:" << size << std::endl;
}
};
//这样使用
int main
{
AnimalHouse<int> elephantHouse(100); // 创建一个大房间给大象住,大小为100
elephantHouse.displaySize(); // 显示这个大房间的大小
AnimalHouse<int> rabbitHouse(50); // 创建一个小房间给兔子住,大小为50
rabbitHouse.displaySize(); // 显示这个兔子的小房间的大小
}
在这个例子中,AnimalHouse
是一个类模板,它接受一个类型参数 T
。这个T可以是任何数据类型,比如int、float或者自定义的数据类型。通过使用类型参数 T
,你可以创建不同大小的房间。
2.函数模板
template<typename T1, typename T2,......,typename Tn>
返回值 函数名(参数列表)
{
}
typename是用来定义模板参数关键字,也可以使用class。切记:不能使用struct代替class。
template <typename T>
T magicBox(T a, T b, bool operation)
{
if (operation)
{
return a + b; // 如果选择加法,就返回两个数的和
}
else
{
return a - b; // 如果选择减法,就返回第一个数减去第二个数的结果
}
}
int main()
{
int a=5;
int b=3;
std::cout<<magicBox<int>(a,b,true)<<std::endl; // 计算5 + 3 = 8并输出结果
std::cout<<magicBox<int>(a,b,false)<<std::endl;// 计算5 - 3 = 2并输出结果
}
在这个例子中,magicBox
是一个函数模板,它接受两个类型参数 T
和一个布尔值 operation
。类型参数 T
可以是任何数据类型,比如int、float或者自定义的数据类型。布尔值 operation
用来决定是做加法还是减法。
类模板 | 函数模板 | |
---|---|---|
定义方式 | 使用template 关键字后跟类型参数 | 与类模板相同 |
适用场景 | 适用于需要创建不同数据类型的对象,并使用相同逻辑处理的场景 | 适用于需要编写处理不同数据类型的通用函数的场景 |
代码复用 | 通过创建模板类的实例来复用代码 | 通过函数模板来复用代码 |
实例化次数 | 类模板的实例化次数与其对象实例的创建次数一致 | 函数模板的实例化次数与其函数的调用次数一致 |
类型参数的使用范围 | 类型参数用于类声明和类实现中的成员函数和成员变量 | 类型参数用于函数声明和函数定义中,也可以用于返回值和参数类型 |
自动数据类型推导 | 不可以 | 不可以 |
二,Typescript 的泛型声明
TypeScript 是 JavaScript 的一个超集(父集),增加了类型检查和其他的特性。在 TypeScript 中,你可以使用泛型来编写可重用的组件或函数,这些组件或函数可以处理多种数据类型。它的泛型有两种分别是泛型函数和泛型类
1.泛型函数
function identity<T>(arg: T): T {
return arg;
}
let output = identity(10);
在上面的例子中,identity
函数是泛型函数。它使用 <T>
来定义一个类型参数,并在函数的参数和返回类型中使用这个类型参数。
2.泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = (x, y) => x + y;
在这个例子中,我们创建了一个名为 GenericNumber
的泛型类,它有一个类型参数 T
。然后我们创建了 GenericNumber
的一个实例 myGenericNumber
,并指定 T
为 number
类型。这样,我们就可以在 myGenericNumber
对象上使用数字操作了。
<T>表示定义模板类型,(value: T): T 表示参数和返回值类型都是同一个类型,具体T是什么类型就实参决定。
C++模板 | TypeScript泛型 | |
---|---|---|
定义方式 | 使用关键字 "template" 来定义函数或类模板 | 使用泛型符号 "<>" 在函数或类声明中定义泛型 |
类型参数 | template<typename T1, typename T2>; (注意这里typename要大写) | <T1, T2> (C++和TypeScript都可以使用多个类型) |
类型检查 | 编译时进行类型检查,可以优化代码 | 运行时进行类型检查,可能影响性能 |
函数模板/泛型函数 | template<typename T> T add(T a, T b) { | function add<T>(a: T, b: T): T { |
类模板/泛型类 | template<typename T> class Box { public: T content; Box(T value); }; | class Box<T> { |
为什么C++和Typescript语言中主张模板和泛型
- 提高代码复用性:通过模板和泛型,程序员可以编写更加通用的代码,这些代码可以在多种数据类型上运行,而不需要为每一种数据类型单独编写代码。这大大减少了重复的代码,并提高了开发效率。
- 提高代码可维护性:模板和泛型允许程序员将算法和数据结构与具体的类型分离,使得代码更加模块化。这使得代码更容易理解和维护,因为主要的逻辑被封装在独立的、可重用的组件中,而不是分散在大量的特定类型代码中。
- 提供更好的类型安全:模板和泛型在编译时进行类型检查,这有助于在早期阶段发现并修复错误,而不是等到运行时才发现。这大大提高了代码的可靠性。
- 提高性能:虽然泛型在运行时可能会引入一些性能开销,但通过使用泛型,程序员可以编写出更加通用的算法和数据结构,这些算法和数据结构可以在编译时进行优化,从而在某些情况下提供更好的性能。
- 支持多范式编程:模板和泛型允许程序员使用多种编程范式,例如面向对象编程、函数式编程等。这使得语言更加灵活,能够更好地满足各种不同的编程需求。