函数模板和类模板 知识点总结 C++程序设计与算法笔记总结(七) 北京大学 郭炜(上)

简介: 函数模板和类模板 知识点总结 C++程序设计与算法笔记总结(七) 北京大学 郭炜(上)

函数模板

交换两个整型变量的值的Swap函数:
void Swap(int & x,int & y) 
{
int tmp = x;
x = y;
y = tmp;
}
交换两个double型变量的值的Swap函数:
void Swap(double & x,double & y) 
{
double tmp = x;
x = y;
y = tmp;
}

用函数模板解决:

用函数模板解决:
template <class 类型参数1,class 类型参数2,……>
返回值类型 模板名 (形参表)
{
函数体
};
template <class T>
void Swap(T & x,T & y) 
{
T tmp = x;
x = y;
y = tmp;
}
函数模板
int main()
{
int n = 1,m = 2;
Swap(n,m); //编译器自动生成 void Swap(int & ,int & )函数
double f = 1.2,g = 2.3;
Swap(f,g); //编译器自动生成 void Swap(double & ,double & )函数
return 0;
}
void Swap(double & x,double & y) 
{
double tmp = x;
x = y;
y = tmp

在C++中,函数模板是一种通用的函数定义,可以应用于不同的数据类型。它允许编写一次代码以适应多种不同的数据类型,实现代码的复用和泛化。

函数模板使用关键字 “template” 开始,并且后面跟着模板参数列表。模板参数列表可以包含一个或多个类型参数(如T、U等)或非类型参数(如整数常量)。例如:

template <typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

上述代码中的函数模板 max 接受两个相同类型的参数,并返回较大的值。类型参数 T 可以是任何数据类型,比如整数、浮点数、字符等。

在实际调用函数模板时,编译器根据参数的类型将模板进行实例化,生成对应类型的函数。例如:

int result1 = max<int>(3, 5);      // 实例化为 max<int>, 返回 5
double result2 = max<double>(2.7, 1.5);  // 实例化为 max<double>, 返回 2.7
char result3 = max<char>('a', 'b');     // 实例化为 max<char>, 返回 'b'

在上面的例子中,通过 <类型> 的形式来指定实例化的具体类型,这样编译器就能够根据传入的类型生成对应的函数。如果没有显式指定类型,编译器会根据参数的类型自动推导出实例化的类型。

函数模板还可以有多个类型参数,并且可以有默认参数值。此外,你还可以在函数模板外定义非模板函数,它们可以与函数模板进行重载。

函数模板是C++中一种强大的工具,利用它可以编写通用且具有复用性的代码,可以处理不同类型的数据。

当需要在函数模板中处理多个不同类型的参数时,可以使用多个类型参数。

例如,下面是一个函数模板 swap,用于交换两个值:

template <typename T>
void swap(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

上述代码中的 swap 函数模板接受两个相同类型的引用参数,并交换它们的值。使用该函数模板时,编译器将根据实参的类型实例化对应的函数。

int x = 5, y = 10;
swap(x, y);  // 实例化为 swap<int>(x, y),交换 x 和 y 的值
double a = 2.5, b = 3.7;
swap(a, b);  // 实例化为 swap<double>(a, b),交换 a 和 b 的值

除了类型参数,函数模板还可以包含非类型参数。非类型参数可以是整数、枚举、指针或引用类型,但不能是浮点数、类类型或 void 类型。

下面是一个示例,演示如何在函数模板中使用非类型参数来指定数组的大小:

template <typename T, int size>
void printArray(const T (&arr)[size]) {
    for (int i = 0; i < size; ++i) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

上述代码中的 printArray 函数模板接受一个固定大小的数组,并打印每个元素。通过将数组大小作为非类型参数传递给函数模板,可以在编译时知道数组的大小。

int intArray[] = {1, 2, 3, 4, 5};
printArray(intArray);  // 实例化为 printArray<int, 5>(intArray)
double doubleArray[] = {1.5, 2.7, 3.9};
printArray(doubleArray);  // 实例化为 printArray<double, 3>(doubleArray)

这样,函数模板就可以根据不同的数组大小生成对应的函数。

需要注意的是,在函数模板的定义和声明中,通常将模板参数放在尖括号 < > 中,并使用关键字 typenameclass 来声明类型参数。然而,你也可以使用非类型参数来调整模板的行为。

同时,函数模板还可以具有默认模板参数,以便更灵活地使用。默认模板参数允许指定某个或某些参数的默认值,使得在函数调用时可以省略掉这些参数。

C++中的函数模板是一种强大的工具,可以处理多个不同类型的参数,其中可以包含类型参数和非类型参数。通过使用函数模板,可以实现通用、可复用的代码,并根据实参的类型和值来自动生成对应的函数。

函数模板和函数的次序

在有多个函数和函数模板名字相同的情况下,编译器如下处理一条函数调用语句

  1. 先找参数完全匹配的普通函数(非由模板实例化而得的函数)。
  2. 再找参数完全匹配的模板函数。
  3. 再找实参数经过自动类型转换后能够匹配的普通函数。
  4. 上面的都找不到,则报错。

类模板

类模板 – 问题的提出

• 为了多快好省地定义出一批相似的类,可以定义类模板,然后由类模

板生成不同的类

• 数组是一种常见的数据类型,元素可以是:

– 整数

– 学生

– 字符串

– ……

• 考虑一个可变长数组类,需要提供的基本操作

– len():查看数组的长度

– getElement(int index):获取其中的一个元素

– setElement(int index):对其中的一个元素进行赋值

– ……

### 类模板的定义

template <typename 类型参数1,typename 类型参数2,……>
//类型参数表
class 类模板名
{
成员函数和成员变量
};
类模板里成员函数的写法:
template <class 类型参数1,class 类型参数2,……> //类型参数表
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表)
{ 
……
}
用类模板定义对象的写法:
类模板名 <真实类型参数表> 对象名(构造函数实参表);
类模板示例: Pair类模板
template <class T1,class T2>
class Pair
{
public:
T1 key; //关键字
T2 value; //值
Pair(T1 k,T2 v):key(k),value(v) { };
bool operator < ( const Pair<T1,T2> & p) const; 
};
template<class T1,class T2>
bool Pair<T1,T2>::operator < ( const Pair<T1,T2> & p) const 
//Pair的成员函数 operator <
{ 
return key < p.key; 
}

类模板示例:Pair类模板

int main()
{
Pair<string,int> student("Tom",19); 
//实例化出一个类 Pair<string,int>
cout << student.key << " " << student.value; 
return 0;
}
输出:
Tom 19

类模板(Class Template)是C++中另一种通用编程的工具,它允许定义一种通用的类,可以用于不同的数据类型。

类模板使用关键字 template 开始,并在尖括号 < > 中包含一个或多个类型参数。类型参数可以在类定义的内部作为类型的占位符使用。例如:

template <typename T>
class MyStack {
private:
    T* elements;
    int top;
    int capacity;
public:
    MyStack(int size) {
        elements = new T[size];
        capacity = size;
        top = -1;
    }
    // 其他成员函数的实现省略...
};

上述代码中的 MyStack 类模板定义了一个栈的数据结构,其中的元素类型 T 是一个占位符,在实际使用时会根据传入的类型进行实例化。

在实际使用类模板时,需要根据实际需求显式实例化特定类型的类。例如:

MyStack<int> intStack(10);       // 实例化为 MyStack<int>
MyStack<double> doubleStack(5);  // 实例化为 MyStack<double>

在上述代码中,分别创建了一个 int 类型和一个 double 类型的 MyStack 对象。每个对象都是根据相应的类型实例化的类。

类模板还可以有多个类型参数,并且可以包含非类型参数,与函数模板类似。可以通过提供特定类型的实参来显式指定实例化的类型,也可以让编译器自动推导类型。

类模板还可以有成员函数、成员变量、构造函数和析构函数等,可以根据具体需求进行实现。在定义类模板的成员函数时,可以像普通类一样使用 T 来引用模板参数所表示的类型。

template <typename T>
class MyStack {
    // ...
    void push(T element) {
        if (top + 1 >= capacity) {
            // 扩展容量代码...
        }
        elements[++top] = element;
    }
    T pop() {
        if (top < 0) {
            // 异常处理代码...
        }
        return elements[top--];
    }
    // ...
};

总结一下,类模板是C++中用于定义通用类的工具,允许创建可以适应不同数据类型的类。类模板使用关键字 template 和类型参数来定义,并通过显式实例化或类型推导来生成特定类型的类。类模板还可以包含成员函数、成员变量等,用于处理特定类型的数据。

用类模板定义对象

编译器由类模板生成类的过程叫类模板的实例化。由类模板实例化得到的类,叫模板类。

同一个类模板的两个模板类是不兼容的

同一个类模板的两个模板类是不兼容的

是的,对于同一个类模板,不同的模板实例(即不同的模板参数)会生成不同的类型,这些类型在编译时是完全独立和不兼容的。

例如,考虑下面的类模板 MyStack

template <typename T>
class MyStack {
    // ...
};

使用 MyStack<int> 实例化的对象和使用 MyStack<double> 实例化的对象是完全不同的类型,它们之间是不兼容的。

MyStack<int> intStack;
MyStack<double> doubleStack;
intStack.push(5);
doubleStack.push(3.14);
int x = intStack.pop();         // 类型为 int
double y = doubleStack.pop();   // 类型为 double

在上述代码中,intStackdoubleStack 是两个完全不同的对象,它们的行为和类型都是根据实例化时的模板参数来确定的。

由于不同的模板实例生成的类型是不兼容的,因此不能将 MyStack<int> 的对象赋值给 MyStack<double> 的对象,也不能将它们混合使用。

MyStack<int> intStack;
MyStack<double> doubleStack;
// 以下代码是不允许的,会导致类型错误:
doubleStack = intStack;          // 错误:不兼容的类型
double x = intStack.pop();       // 错误:类型不匹配
intStack.push(3.14);             // 错误:类型不匹配

因此,对于同一个类模板生成的不同模板实例,它们是不兼容的,并且在使用时需要注意保持类型一致。

目录
相关文章
|
4天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
1天前
|
存储 监控 算法
员工屏幕监控系统之 C++ 图像差分算法
在现代企业管理中,员工屏幕监控系统至关重要。本文探讨了其中常用的图像差分算法,该算法通过比较相邻两帧图像的像素差异,检测屏幕内容变化,如应用程序切换等。文中提供了C++实现代码,并介绍了其在实时监控、异常行为检测和数据压缩等方面的应用,展示了其实现简单、效率高的特点。
27 15
|
1天前
|
算法 Serverless 数据处理
从集思录可转债数据探秘:Python与C++实现的移动平均算法应用
本文探讨了如何利用移动平均算法分析集思录提供的可转债数据,帮助投资者把握价格趋势。通过Python和C++两种编程语言实现简单移动平均(SMA),展示了数据处理的具体方法。Python代码借助`pandas`库轻松计算5日SMA,而C++代码则通过高效的数据处理展示了SMA的计算过程。集思录平台提供了详尽且及时的可转债数据,助力投资者结合算法与社区讨论,做出更明智的投资决策。掌握这些工具和技术,有助于在复杂多变的金融市场中挖掘更多价值。
22 12
|
1月前
|
负载均衡 算法 安全
探秘:基于 C++ 的局域网电脑控制软件自适应指令分发算法
在现代企业信息化架构中,局域网电脑控制软件如同“指挥官”,通过自适应指令分发算法动态调整指令发送节奏与数据量,确保不同性能的终端设备高效运行。基于C++语言,利用套接字实现稳定连接和线程同步管理,结合实时状态反馈,优化指令分发策略,提升整体管控效率,保障网络稳定,助力数字化办公。
52 19
|
1天前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
1天前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。
|
1天前
|
存储 程序员 C语言
【C++篇】深度解析类与对象(上)
在C++中,类和对象是面向对象编程的基础组成部分。通过类,程序员可以对现实世界的实体进行模拟和抽象。类的基本概念包括成员变量、成员函数、访问控制等。本篇博客将介绍C++类与对象的基础知识,为后续学习打下良好的基础。
|
3月前
|
搜索推荐 Python
利用Python内置函数实现的冒泡排序算法
在上述代码中,`bubble_sort` 函数接受一个列表 `arr` 作为输入。通过两层循环,外层循环控制排序的轮数,内层循环用于比较相邻的元素并进行交换。如果前一个元素大于后一个元素,就将它们交换位置。
155 67
|
1月前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
70 19
|
1月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
52 13