C++模板(template)详解教程(很多代码示例)

目录

1. 定义模板

1.1. 函数模板

实例化函数模板

模板类型参数

非类型模板参数

inline 和 constexpr的函数模版

编写类型无关的代码

模版编译

1.2. 类模版

定义类模版

实例化类模版

类模版的成员函数

类模版构造函数

在类模版外使用类模版名

在类模版中的友元

类模版的static成员

1.3. 模版参数

模版声明

使用typename来区分成员和类型

默认模板实参

模板默认实参与类模板

1.4. 成员模板

非模板类的成员模板

类模板的成员模板

实例化与成员模板

1.5. 继承关系

父类是一般类,子类是模板类

父类是模板类,子类是普通类

父类和子类都是模板类

注意事项


  面向对象编程(OOP)泛型编程都能处理在编写程序时不知类型的情况,不同之处在于:OOP能处理类型在程序运行之前都未知的情况:而在泛型编程中,在编译时就能获知类型了

1. 定义模板

1.1. 函数模板

背景:比如我们需要来比较不同数据类型的两个值,并指出第一个值与第二个值的大小关系,如果此时只定义只比较一种参数类型的函数,略显麻烦。

此时引出了函数模板,此时就不用为每个类型定义一个新的函数了。

比如:

template<typename T>
int compare(const T& v1, const T& v2)
{
	if (v1 < v2)return -1;
	if (v2 < v1)return 1;
	return 0;
}

模版定义:以关键字template开始,后跟一个模板参数列表,这是一个逗号分隔的一个或多个模板参数的列表,用小于号(<)和大于号(>)包围起来。

实例化函数模板

当我们调用一个函数模版时,编译器通常根据函数传入的实参来推断模板实参

例如,

cout << compare(1, 0) << endl;//T为int

实参为int型,编译器会将模板实参推断为int,并将它绑定到模板参数T

  • 编译器用推断出的模板参数来为我们实例化,这些编译器生成的版本通常被称为模板的实例
模板类型参数

在模板参数列表中,使用关键字typenameclass后面跟着一个标识符来定义模板类型参数。例如:

template<typename T>
void print(T value) {
    std::cout << value << std::endl;
}

在上面的例子中,T是一个模板类型参数,它表示一个不特定的数据类型。在函数体内,我们可以像使用任何其他类型一样使用T

  • 返回类型和参数类型相同的模板示例:
template<typename T>
T identity(T value) {
    return value;
}

在上面的例子identity 是一个模板函数,它接受一个参数 value,类型为 T,并返回相同类型的值。无论传入什么类型的参数,该函数都会返回相同类型的值。

使用该模板函数的示例代码如下:

int main() {
    int intValue = identity(42);  // 返回 int 类型的值 42
    double doubleValue = identity(3.14);  // 返回 double 类型的值 3.14
    std::string stringValue = identity("Hello");  // 返回 std::string 类型的值 "Hello"

    return 0;
}

在上述示例中,identity 函数根据传入的参数类型进行实例化,并返回相同类型的值。

模板类型参数前必须使用关键字 classtypename,这是为了指示编译器该参数是一个类型参数。

选择使用哪个关键字主要是个人偏好,但在C++标准中,更常见的做法是使用关键字 typename 来表示类型参数

非类型模板参数

非类型模板参数(Non-type Template Parameters):非类型模板参数允许我们在模板中使用常量值作为参数。它们用于在模板定义中指定一个常量值,而不是一个数据类型。非类型模板参数可以是整数、枚举、指针或引用类型。在模板参数列表中,我们使用一个特定的类型来定义非类型模板参数。例如:

template<int N>
int multiplyByN(int value) {
    return value * N;
}

在上面的例子中,N是一个非类型模板参数,它表示一个整数常量值。在函数体内,我们可以将N用作常量值来执行相应的计算。

  • 非类型模版参数使用示例:

模版定义了两个非类型的参数。第一个模板参数表示第一个数组的长度,第二个模版参数表示第二个数组的长度:

template<unsigned N,unsigned M>
int compare(const char(&p1)[N], const char(&p2)[M])
//由于数组不能拷贝,所以定义为数组的引用
{
	return strcmp(p1, p2);
}
​

当我们这样调用时:

compare("hi","mom");

编译器会使用字面常量的大小来代替N和M,从而实例化模版:

int compare(const char (&p1)[3],const char (&p2)[4])
  • 一个非类型参数可以是一个整型,或者是一个指向对象或函数类型的指针或(左值)引用
  • 绑定到非类型整型参数的实参必须是一个常量表达式
  • 在模版定义内,模版非类型参数是一个常量值。在需要常量表达式的地方,可以使用非类型参数。例如指定数组大小
inline 和 constexpr的函数模版

函数模版可以声明为inline或constexpr的,如同非模版函数一样。inline或constexpr说明符放在模版参数列表之后,返回类型之前:

//正确:inline说明符跟在模版参数列表之后
template <typename T> inline T min(const T&,const T&);
//错误:inline 说明符的位置不正确
inline template<typename T> T min(const T&,const T&);
编写类型无关的代码
  1. 将参数设定为
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值