c++模板的概念全新解释(二)

简介: c++模板的概念全新解释(二)

类模板定义


类是对一组对象的公共性质的抽象,而类模板则是对不同类的公共性质的抽象,英雌类模板属于是更高层次的抽象。

格式:

template<模板参数表>

class <类模板名>

{

<类成员声明>

}

其中,<模板参数表>中包含一个或多个用逗号隔开的类型,参数项可以包含数据类型,也可以包含类属类型,如果是类属类型,则必须加class或者typename做前缀。

类模板中的成员函数的定义:

template<模板参数表>

返回值类型<类模板名><类型列表>::<函数名>(参数表)

{

函数体

}

<类型名表>既是类模板中定义中的类型形式参数表中的参数名。

类模板中的成员函数放在类模板的外部的时候,也可以在前面加inline表明内连函数函数。


类模板的实例化


与函数模板不同的是,函数模板的实例化是由编译系统在处理函数调用时自动完成,而类模板的实例化必须由程序员在程序中显示的指定。


1b77cb37672fc7fdc918bae258e01957_39d7f97c081841699adc82affd05f2fd.png


代码演示:


#include<iostream>
#include<process.h>
using namespace std;
const int size = 10;
template <typename AType>
class atype
{
public:
  atype()
  {
  int i;
  for (i = 0; i < size; i++)
  {
    array[i] = i;
  }
  }
  AType& operator[](int n);
private:
  AType array[size];
};
template <typename AType>
AType& atype<AType>::operator[](int n)
{
  if (n<0 || n>size)
  {
  cout << "下标" << n << "超出范围!" << endl;
  exit(1);
  }
  return array[n];
}
int main()
{
  const int size = 10;
  atype<int>intob;
  atype<double>doubleob;
  int i;
  cout << "Integer 数组:";
  for (i = 0; i < size; i++)
  intob[i] = i;
  for (i = 0; i < size; i++)
  {
  cout << intob[i] << " ";
  }
  cout << endl;
  cout << "Double 数组:";
  for (i = 0; i < size; i++)
  {
  doubleob[i] = (double)i / 2;
  }
  for (i = 0; i < size; i++)
  {
  cout << doubleob[i] << " ";
  }
  cout << endl;
  intob[12] = 100;         //下标越界;
  return 0;
}


8cb69e507ebf537d575f7b8f09cee72f_a8cec7ef5fbf45feaf720e3e0f3cf6e1.png


类模板的实例化创建的结果是一种类型,而类的实例化创建的结果则是一个对象。


ebe90f3e1ae2d32cea3bfe09027bf012_c9b58d09d21e455bb91d683ade48f251.png


使用函数类型参数的类模板


在类模板的《模板参数表中》,必须至少有一个类参数,当然也可以有多个类参数。还可以有非类参数的参数,这样的参数一般称之为函数类型参数,也可以称之为无类型模板参数。

函数参数类型只限于整型,指针和引用,其他的类型(例如浮点型float)则不能使用。传递给函数参数类型的实参要么是整型常量,要么由指向全局函数或对象的指针或引用组成。由于函数参数类型的值不能改变,所以函数参数类型参数本身被看作常量,因此,函数类型参数可以用来设定数组大小。


#include<iostream>
#include<process.h>
using namespace std;
template <typename AType,int size>             //size作为函数参数类型参数
class atype          //模板类;
{
public:
  atype()
  {
  int i;
  for (i = 0; i < size; i++)
    array[i] = i;
  }
  AType& operator[](int n);    //"[]"运算符重载;至少含有一个参数;
private:
  AType array[size];
};
template <typename AType,int size>
AType& atype<AType, size>::operator[](int n)
{
  //下标越界检查;
  if (n<0 || n>size)
  {
  cout << "下标" <<n<<"超出范围" << endl;
  exit(1);
  }
  return array[n];
}
int main()
{
  //10个元素的integer数组类,intob为该类的一个对象;
  atype<int, 10>intob;
  //10个元素的double数组类,doublob为该类的一个对象
  atype<double, 10>doublob;
  int i;
  cout << "integer[]数组类: ";
  for (i = 0; i < 10; i++)
  {
  intob[i] = i;
  cout << intob[i] << "  ";
  }
  cout << endl;
  cout << "doublob[]数组类: ";
  for (i = 0; i < 10; i++)
  {
  doublob[i] = (double)i / 2;
  cout << doublob[i] << "  ";
  }
  cout << endl;
  intob[12] = 100;
  return 0;
}


e80dcb4dd7e692b8e12b93477e6fe2f2_dba54d7409c744bd9c30f1413a34fc98.png



使用默认参数的类模板


类模板可以包含于通用类型相关的默认参数。当类模板被实例化时,如果没有指定其他的数据类型,则使用默认数据类型。


#include<iostream>
#include<process.h>
using namespace std;
template<typename AType=int,int size=10>
class atype           //使用默认参数的模板类;
{
public:
  atype()
  {
  int i;
  for (i = 0; i < size; i++)
  {
    array[i] = i;
  }
  }
  AType& operator[](int n);
private:
  AType array[size];
};
template<typename AType,int size>
AType& atype<AType, size>::operator[](int n)
{
  if (n<0 || n>size)
  {
  cout << "下标" << n << "越界" << endl;
  exit(1);
  }
  return array[n];
}
int main()
{
  //12个元素的integer数组类,inton为模板类的一个对象;
  atype<int,12>intob;
  //double数组类,默认10个元素长度,
  atype<double>doubleob;
  //数组类,默认int型,默认10个元素长度;
  atype<>defaultob;
  int i;
  cout << "Integer 数组类:";
  for (i = 0; i < 12; i++)
  {
  intob[i] = i;
  cout << intob[i] << "  ";
  }
  cout << endl;
  cout << "double 数组类:";
  for (i = 0; i < 10; i++)
  {
  doubleob[i] = (double)i / 2;
  cout << doubleob[i] << "  ";
  }
  cout << endl;
  cout << "默认参数类型:";
  for (i = 0; i < 10; i++)
  {
  cout << defaultob[i] << "  ";
  }
  cout << endl;
  return 0;
}


e8499ef84e419ad81a56dae390e08c72_02861898d4d44f1bba23ebf86e30c083.png



标准模板库STL


c++中包含一个有许多组件的标准库。标准模板库(Standard Template Library,STL)是标准c++标准库的一部分。


容器


“容器”是数据结构,是包含对象的对象。例如,数组,队列,堆栈,树,图等数据结构中的每一个节点都是一个对象。这些结构按照某种特定的逻辑关系组合在一起,就成为了一个新的对象。


容器的分类


f6aebb8e8cf78728962317b631d04f1f_75938749b9de4cdeb7d09a7b40290efe.png


b73bcdd571a9748a49d22349b7b27c7d_b36d2f44cc574ea5a852f1656e0bd5cd.png


在前面介绍c++基础知识的时候,就已经介绍了STL模板库,但是很多人并不知道他的原理,而要想弄懂这个问题就要知道容器的接口是什么。

我们所使用的STL模板斗都是将一些代码封装为一个容器,从而使用它,正是由于这样才使得我们的工作减轻很多负担。要想正确的使用模板,了解他们所对应的函数原型显得很重要。下面我们以vector模板为例,介绍他的原函数:


顺序容器和关联容器


顺序容器将一组具有相同类型的元素一样额的线性形式组织起来。顺序容器分为vector,list,deque三种类型。他们在某些方面很相似。前面已经介绍过了,就不过多介绍。

关联容器具有根据一组索引来快速提取元素的能力,其中元素可以通过键值(key)来访问。四种关联容器可以分为两种:set和map

(1).set是一种集合,其中可以包含0个或多个不重复的以及不排序的元素,这些元素被称为键值。

例如,set集合s

{-2,34,56}

中包含三个键值,不能通过下标来访问集合;

(2).map是一种映像,其中包含0个或多个不排序的元素对,一个元素是不重复的键值,另一个是与键相关联的值。

例如,map集合m

{(first,4),(second,-99),(third,50)}

中包含3对元素。每对元素都由一个键值和相关联的值构成。

map和multimap容器的元素是按照关键字顺序排列的,因此提供按关键字快速查找元素。成员函数find(),count(),lower_bound(),upper_bound()基于元素键值的查找和计数。


#include<iostream>
#include<vector>
#include<process.h>
using namespace std;
int main()
{
  int i;
  vector<int>nums;        //整型向量,长度为0;
  nums.insert(nums.begin(), -99);    //在第一处插入数据-99
  nums.insert(nums.begin(), 50);
  nums.insert(nums.end(), 4);
  for (i = 0; i < nums.size(); i++)
  {
  if (nums[i])
  cout << nums[i] << " ";
  }
  cout << endl;
  nums.erase(nums.begin());  //删除向量中第一处的值
  nums.erase(nums.begin());
  for (i = 0; i < nums.size(); i++)
  {
  if(nums[i])
  cout << nums[i] << "  ";
  }
  cout << endl;
  return 0;
}


2dda2f998a3ca1f755e993c07274159a_2ff1f3cdd6b54371b113a48f3952e702.png


迭代器


对于迭代器的理解,可以理解为面向对象版本的指针,但是和指针又有一些不同。通俗点来说就是指针是迭代器,但迭代器又不仅仅是指针,指针可以指向内存中的一个地址,然后通过这个地址访问相应的内存单元。而迭代器更抽象,它可以指向容器中的一个位置,然后就可以直接访问这个位置的元素。


迭代器的分类


STL迭代器主要包括5中基本类别:输入(input)迭代器,输出(output)迭代器,前向(forward)迭代器,双向(bidirectional)迭代器和随机访问(random access)迭代器。


6cea8dce1c1087deee20daa662b564bb_eea079bd482a431da0dc936061bf9920.png


迭代器在头文件iterator中声明。因为不同类型的容器支持不同的迭代器,所以不必显式指定包含iterator文件也可以使用迭代器。

vector和deque容器支持随机访问。list,map,set,multiset和multimap支持双向访问;


迭代器的使用


可以定义各种容器的迭代器对象(iterator类型对象)。迭代器对象通常被称为迭代子或迭代算子。

eg:


#include<iostream>
#include<list>
#include<iterator>      //迭代器头文件可以省略;
using namespace std;
int main()
{
  list<int>nums;  //整型双向链表
  for (int i = 0; i < 10; i++)
  {
  nums.insert(nums.end(), i * 10);
  }
  list<int>::const_iterator p1; //p1是双向链表的迭代子;
  cout << "整型双向链表的正向输出:" << endl;
  for (p1 = nums.begin(); p1 != nums.end(); p1++)     //这里p1不再是用循环中常用的小于来判断循环结束条件;
  {
  cout << *p1 << "  ";
  }
  cout << endl;
  list<int>::reverse_iterator p2;
  p2 = nums.rbegin();           //反向迭代指向最后一个元素;
  cout << "逆向输出双向链表中所有元素:" << endl;
  while (p2 != nums.rend())
  {
  cout << *p2 << "  ";
  p2++;
  }
  cout << endl;
  return 0;
}


3bbcd0f55df6efe362dd40609cb9b9fe_f89877187069485d862961aef126517b.png



上面的程序中在使用迭代器的时候,我们发现迭代器的定义有点不一样,那么他们的差距在哪里?


预定义迭代器


预定义迭代器 ++操作方向

iterator 向前

const_iterator 向前

reverse_iterator 向后

const_ireverse_terator 向后

算法

c++中的STL中包含大约70种标准算法。这些算法是用于对容器的数据施加特定操作的函数模板。

STL中几乎所有的算法的头文件都是#include

从对容器的访问性质来说,算法分为只读(及不允许改写元素)和改写(即可以修改元素)两种。从功能上来说可以分为查找,比较,计算,排序,置值,合并,集合,管理等。


通用算法的调用形式

如同STL容器是常用数据结构的类模板一样,STL算法是用于对容器的数据施加特定操作的函数模板。

例如STL中的排序算法:

第一种形式:


template<typename RandomAcessIterator>
void sort(RandomAcessIterator first,RandomAcessIterator last);


按照升序排列;

第二种形式:


template<RandomAcessIterator,class Compare>
void sort(RandomAcessIterayor first,RandomAcessIterator last,Compare pr)


按照pr函数的排序方式来排序。


通用算法应用


//reverse和sort的应用
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
bool inoder(int, int);
int main()
{
  vector<int>nums;      //整型向量,长度为;
  for (int i = 0; i < 10; i++)
  {
  nums.insert(nums.end(), i * 10);
  }
  cout << "向量的初始顺序:";
  vector<int>::const_iterator p1;
  for (p1 = nums.begin(); p1 != nums.end(); p1++)
  {
  cout << *p1 << "   ";
  }
  cout << endl;
  //函数逆置;
  reverse(nums.begin(), nums.end());
  cout << "逆置排列:";
  for (int i = 0; i < 10; i++)
  {
  cout << nums[i] << "  ";
  }
  cout << endl;
  //调用第一种排序方式排序;
  sort(nums.begin(), nums.end());
  cout << "使用第一种方式排序后的结果为:";
  for (int i = 0; i < 10; i++)
  {
  cout << nums[i] << "  ";
  }
  cout << endl;
  //调用第二种方式排序
  sort(nums.begin(), nums.end(), inoder);
  vector<int>::const_iterator p2;
  cout << "第二种排序方式的输出结果:";
  for (p2 = nums.begin(); p2 != nums.end(); p2++)
  {
  cout << *p2 << "  ";
  }
  cout << endl;
}
bool inoder(int a, int b)
{
  return a > b;
}


f00c15dd1795ff556689817741719458_c2cd6a9cbd68439090b6e3b8e6afc587.png

相关文章
|
8天前
|
编译器 C语言 C++
c++的学习之路:19、模板
c++的学习之路:19、模板
30 0
|
23天前
|
存储 C++ 容器
C++STL(标准模板库)处理学习应用案例
【4月更文挑战第8天】使用C++ STL,通过`std:vector`存储整数数组 `{5, 3, 1, 4, 2}`,然后利用`std::sort`进行排序,输出排序后序列:`std:vector<int> numbers; numbers = {5, 3, 1, 4, 2}; std:sort(numbers.begin(), numbers.end()); for (int number : numbers) { std::cout << number << " "; }`
21 2
|
2天前
|
运维 Serverless Go
Serverless 应用引擎产品使用之在阿里云函数计算中c++模板,将编译好的C++程序放进去部署如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
9 1
|
2天前
|
存储 C++
【C++模板】模板实现通用的数组
【C++模板】模板实现通用的数组
|
7天前
|
编译器 程序员 C++
C++从入门到精通:3.1模板编程——提高代码的复用性和灵活性
C++从入门到精通:3.1模板编程——提高代码的复用性和灵活性
|
7天前
|
存储 人工智能 编译器
【重学C++】【指针】一文看透:指针中容易混淆的四个概念、算数运算以及使用场景中容易忽视的细节
【重学C++】【指针】一文看透:指针中容易混淆的四个概念、算数运算以及使用场景中容易忽视的细节
18 1
|
7天前
|
编译器 C语言 C++
【C++进阶(七)】仿函数深度剖析&模板进阶讲解
【C++进阶(七)】仿函数深度剖析&模板进阶讲解
|
7天前
|
存储 编译器 对象存储
【C++基础(十)】C++泛型编程--模板初阶
【C++基础(十)】C++泛型编程--模板初阶
【C++基础(十)】C++泛型编程--模板初阶
|
8天前
|
Linux C++
c++的学习之路:24、 二叉搜索树概念
c++的学习之路:24、 二叉搜索树概念
30 1
|
8天前
|
存储 编译器 Linux
c++的学习之路:8、内存管理与模板
c++的学习之路:8、内存管理与模板
9 0