c++学习记录(四)

1、函数模版

模版是c++参数多态的工具,模版一般有类模板和函数模版,使得类中的某些数据或者函数成员可以支持任意类型的参数。同时返回值也是一样的,可以取得任意类型。

通过使用模版:

能够使程序员编写和类型无关的代码,比如下面编写一个经典的交换代码,默认的话我们需要指定参数类型,例如整形,那我们就只能对整数类型进行交换,这样我们如果要对浮点数进行交换就很蛮烦,使用模版就可以实现这个与类型无关。

1、函数模版的概念

函数模版的使用在上面已经介绍过了,这里不在赘述,下面是函数模版的基本语法:

template<typename T>
函数声明或定义

说明如下:

  • template — 声明创建模板
  • typename — 表面其后面的符号是一种数据类型,可以用class代替
  • T — 通用的数据类型,名称可以替换,通常为大写字母

2、函数模版例子

下面用一个交换函数来用模版的方式来进行表达:

代码如下:

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

使用模版有两种方式可以进行,如下所示:
在这里插入图片描述
使用模版进行比较效果如下:
在这里插入图片描述
当然这里还是要相同类型的参数进行比较,不然还是会报错的:
在这里插入图片描述

因此可以看出,使用函数模版的优势在于:

  • 函数模板利用关键字 template
  • 使用函数模板有两种方式:自动类型推导、显示指定类型
  • 模板的目的是为了提高复用性,将类型参数化

3、使用函数模版来实现多种排序

下面来使用函数模版实现不同类型数据的排序,这里还是用最经典的冒泡排序的方式来实现,根据之前介绍的冒泡排序需要我们进行逐一的筛选然后替换,所以这里需要两个函数模版,如下所所示:
在这里插入图片描述
代码如下:

template<typename T>
void mySwap(T &a, T&b)
{
    
    
	T temp = a;
	a = b;
	b = temp;
}
template<typename T>
void mySort(T arr[], int len)
{
    
    
	for (int i = 0; i < len; i++)
	{
    
    
		int max = i; //最大数的下标
		for (int j = i + 1; j < len; j++)
		{
    
    
			if (arr[max] < arr[j])
			{
    
    
				max = j;
			}
		}
		if (max != i) //如果最大数的下标不是i,交换两者
		{
    
    
			mySwap(arr[max], arr[i]);
		}
	}
}

下面是测试的函数:
在这里插入图片描述
运行结果如下所示:
在这里插入图片描述

2、类模板

1、类模板的概念

类模板的作用为:

  • 建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。

使用类模板的语法如下所示:

template<typename T>
类

参数说明如下:

  • template — 声明创建模板
  • typename — 表面其后面的符号是一种数据类型,可以用class代替
  • T — 通用的数据类型,名称可以替换,通常为大写字母

2、类模板使用示例

下面是一个类模板的使用示例,如下所示:
在这里插入图片描述
代码如下:

template<typename NameType, typename AgeType>
class Person
{
    
    
public:
	Person(NameType name, AgeType age)
	{
    
    
		this->mName = name;
		this->mAge = age;
	}
	void showPerson()
	{
    
    
		cout << "name: " << this->mName << " age: " << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

指定参数类型,调用这个模版
在这里插入图片描述
运行结果如下所示:
在这里插入图片描述

3、类模板和函数模版的区别

这里类模板与函数模板区别主要有两点:

  1. 类模板没有自动类型推导的使用方式
  2. 类模板在模板参数列表中可以有默认参数

在这里插入图片描述

4、类模板中成员函数的创建时机

类模板中成员函数的规则如下所示,相比普通类中而言:

  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数在调用时才创建

下面是一个示例:
在这里插入图片描述
下面是使用过程的影响,这里如果调用第二个成员函数就会报错
在这里插入图片描述
这是因为:类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成
在这里插入图片描述
代码如下:

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

class Person1
{
    
    
public:
	void showPerson1()
	{
    
    
		cout << "Person1 show" << endl;
	}
};
class Person2
{
    
    
public:
	void showPerson2()
	{
    
    
		cout << "Person2 show" << endl;
	}
};

template<class T>
class MyClass
{
    
    
public:
	T obj;
	void fun1() {
    
     obj.showPerson1(); }
	void fun2() {
    
     obj.showPerson2(); }
};

void test01()
{
    
    
	MyClass<Person1> m;
	m.fun1();
	m.fun2();
}

int main() 
{
    
    
	test01();
	system("pause");
	return 0;
}

5、类模板对象做函数参数

类模板实例化出的对象,向函数传参一共有三种传入方式:

  1. 指定传入的类型 — 直接显示对象的数据类型
  2. 参数模板化 — 将对象中的参数变为模板进行传递
  3. 整个类模板化 — 将这个对象类型 模板化进行传递

下面举例来表述这个方式,首先还是先新建一个类模版:

template<class NameType, class AgeType = int>
class Person
{
    
    
public:
	Person(NameType name, AgeType age)
	{
    
    
		this->mName = name;
		this->mAge = age;
	}
	void showPerson()
	{
    
    
		cout << "name: " << this->mName << " age: " << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

类模板进行函数参数的传递一共有三种方式,如下所示:

  • 指定参数类型和参数名称直接传入(这种跟普通的参数传入没什么区别):
    在这里插入图片描述
  • 将参数模版化传入
    在这里插入图片描述
  • 直接将整个类模版化
    在这里插入图片描述

一般第一种比较常用,和普通的传入参数的方法也是一样的。

3、STL

1、STL的基本概念

主要是为了避免重复造轮子的繁琐工作才会产生STL这样的方法,C++的面向对象泛型编程思想,目的就是复用性的提升,大多情况下,数据结构和算法都未能有一套标准,导致被迫从事大量重复工作,因此为了建立数据结构和算法的一套标准,诞生了STL

2、STL介绍

STL从大的框架上主要包含:

  • STL(Standard Template Library,标准模板库)
  • STL 从广义上分为: 容器(container) 算法(algorithm) 迭代器(iterator)
  • 容器算法之间通过迭代器进行无缝连接。
  • STL 几乎所有的代码都采用了模板类或者模板函数

STL大体分为六大组件,分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

  1. 容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据。
  2. 算法:各种常用的算法,如sort、find、copy、for_each等
  3. 迭代器:扮演了容器与算法之间的胶合剂。
  4. 仿函数:行为类似函数,可作为算法的某种策略。
  5. 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。
  6. 空间配置器:负责空间的配置与管理。

STL中容器、算法、迭代器

  • STL容器就是将运用最广泛的一些数据结构实现出来

常用的数据结构:数组, 链表,树, 栈, 队列, 集合, 映射表 等
这些容器分为序列式容器关联式容器两种:
序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置。
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系

  • 有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(Algorithms)

算法分为:质变算法非质变算法
质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等等
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等

  • 迭代器:容器和算法之间粘合剂

提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。
每个容器都有自己专属的迭代器
迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针

迭代器种类:

种类 功能 支持运算
输入迭代器 对数据的只读访问 只读,支持++、==、!=
输出迭代器 对数据的只写访问 只写,支持++
前向迭代器 读写操作,并能向前推进迭代器 读写,支持++、==、!=
双向迭代器 读写操作,并能向前和向后操作 读写,支持++、–,
随机访问迭代器 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 读写,支持++、–、[n]、-n、<、<=、>、>=

常用的容器中迭代器种类为双向迭代器,和随机访问迭代器

3、容器

下面来通过示例查看这三个比较重要概念的额应用情况,这三者的名称如下所示:

容器: vector
算法: for_each
迭代器: vector<int>::iterator

下面举一个容器中输入数据然后遍历输出的例子,可以看出其实这个容器还是很像一个数组的,或者python中的列表。
在这里插入图片描述
输出结果如下:
在这里插入图片描述
代码如下

#include <vector>
#include <algorithm>

void MyPrint(int val)
{
    
    
	cout << val << endl;
}

void test01() 
{
    
    
	vector<int> v;//创建一个容器

	//向容器中放数据
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);

	vector<int>::iterator pBegin = v.begin();//获取元素开头和结尾方便后续使用
	vector<int>::iterator pEnd = v.end();

	cout << "第一种遍历" << endl;
	while (pBegin != pEnd) 
	{
    
    
		cout << *pBegin << endl;
		pBegin++;
	}

	cout << "第二种遍历" << endl;
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) 
	{
    
    
		cout << *it << endl;
	}
	cout <<"第三种遍历"<< endl;
	for_each(v.begin(), v.end(), MyPrint);
}

int main() {
    
    

	test01();
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_51220742/article/details/125652020
今日推荐