我是靠谱客的博主 强健小蝴蝶,最近开发中收集的这篇文章主要介绍泛型编程风格,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

一.指针的算术运算

二.了解Iterator(泛型指针)

三.所有容器的共通操作

四.使用顺序性容器

五.使用泛型算法

六.设计泛型算法

七.map和set

八.使用iostream iterator


一.指针的算术运算

利用指针的算术运算完成find()函数的c++代码:

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

template<typename T1,typename T2>
T1* find(const T1* first, const T1* last, const T2 value) //第一和第二个参数用于表示所搜索的容器范围(两个指针表示范围),第三个参数为在容器中搜索的值。
{
	if (!first || !last)
	{
		return 0;
	}
	for (; first != end; first++) //end指针所指的位置应该是容器最后一个元素的下一个地址,这样才可以保证容器中的所有元素都经过了扫描
	{
		if (*first == value)
		{
			return first;
		}
	}
	return 0;
}


int main()
{
	int arr1[5] = { 5,3,10,9,6 };
	int* p1 = find(arr1, arr1 + 5, 9); //第一个参数是容器的首地址,第二个参数是容器的最后一个元素的下一个地址,即为尾地址
	if (p1 != (arr1 + 5))
	{
		cout << "找到了,地址为:" <<p1<< endl;
	}
	else
	{
		cout << "没找到" << endl;
	}

	system("pause");
	return 0;
}

知识点:

1.*(array+i) 与 array[i]的效果相同,下标操作就是将array的起始地址加上索引值,产出某个元素的地址,然后该地址再被提纲以返回元素值。

2.对于数组最后一个元素的下一个地址,只能对此地址进行比较,而不能用来读取和写入。

eg:

int ia[5] = {1,2,3,4,5};
int a1 = *(ia+6);//错误,对最后一个元素的下一个地址不能用来读取和写入
find(ia,ia+5,ia[3]);//正确,对最后一个元素的下一个元素可以用来比较

3.array数组不能为空,但是vector数组可以为空,同时vector类含有函数“ .empty "来判断一个vector数组是否为空。

4.对于list容器,不适用于指针的算术运算,因为指针的算术运算必须首先假设所有元素都存储在连续的空间里,但是list容器不存储在连续的空间里,其每个节点都有三个值:front指向上一个节点,next指向下一个节点,value表示节点的值。

参考文章:C++ list(STL list)容器完全攻略(超级详细) (biancheng.net)

5.list容器适用于存储常需要修改(插入删除操作)而不常读取的数据,而vector和array容器适用于存储常读取而不常修改(插入删除操作)的数据。

二.了解Iterator(泛型指针)

通过iterator指针实现find()函数的C++代码:

#include<iostream>
#include<vector>
#include<list>
#include<iterator>
using namespace std;

const int asize = 5;

template<typename IteratorType,typename elemType>
IteratorType find1(IteratorType first, IteratorType last,const elemType value) //同理,第一个参数是容器的第一个元素的地址,而第二个参数是容器最后一个元素的下一个地址
{
	for (; first != last; first++)
	{
		if (*first == value)
		{
			return first;
		}
	}
	return last; //此地址只可以用来比较,而不能用来读取和写入
}

int main()
{
	int ia[asize] = { 1,5,10,20,95 };
	vector<int> ivec(ia, ia + asize);
	list<int>ilist(ia, ia + asize);

	int* pia = find1(ia, ia + asize, 20);
	if (pia != 0)
	{
		cout << "找到了" << endl;
	}

	vector<int>::iterator iter1;
	iter1 = find1(ivec.begin(), ivec.end(), 100);
	if (iter1 != ivec.end())
	{
		cout << "找到了" << endl;
	}

	list<int>::iterator iter2;
	iter2 = find1(ilist.begin(), ilist.end(), 95);
	if (iter2 != ilist.end())
	{
		cout << "找到了" << endl;
	}

	system("pause");
	return 0;
}

支持两种形式:一对指针或是一对指向某种容器的iterator

知识点:

1.对于不同类型的iterator指针,其运算符进行的操作是根据iterator class内相关的inline函数提供的。

eg:

//first是一个iterator泛型指针
first++;
//如果first是vector的泛型指针,则first++则是将目前的地址加上一个元素的大小。
//如果first是list的泛型指针,则first++则是会沿着list的指针前进到下一个元素。

2.每个标准容器都提供有一个begin()的操作函数,可返回一个iterator指向第一个元素, 也提供一个end()的操作函数指向最后一个元素的下一位置。

3.定义iterator:需要提供两个参数

(1).迭代对象(即为某个容器)的类型,用来决定如果访问下一元素。

(2).iterator所指的元素类型,可以决定iterator提领操作的返回值。

//iterator<vector,string> iter1;
//iterator<list,int> iter2;
//实际语法:
vector<string>::iterator iter1;
list<int>::iterator iter2;

4.const_iterator:只可读而不可进行其他操作

vector<string>::const_iterator iter;

5.通过iterator指针访问容器内的操作:间接访问( -> )

vector<string>::iterator iter;
int size = iter->size();

三.所有容器的共通操作

①." == " 和 "!="运算符,返回true或false。

②."="运算符,将某个容器复制给另一个容器。

③.empty()会在容器无任何元素时返回true,否则返回false。

④.size()返回容器内目前持有的元素个数。

⑤.clear()删除所有元素。

⑥.begin()返回一个iterator指向容器的第一个元素,end()返回一个iterator指向容器的最后一个元素的下一位置。

⑦.insert()将单一或某个范围内的元素插入容器内,erase()将容器内的单一元素或者某个范围内的元素删除。

四.使用顺序性容器

1.顺序容器用来维护一组排列有序、类型相同的元素。

2.顺序性容器种类:

①.vector:以一块连续内存来存放元素,其中的每个元素都被存储在距离起始点的固定偏移位置上,随机访问效率较高,而对于任意位置的插入或删除操作缺乏效率。

②.list:以双向链接而非连续内存来存储内容,对于任意位置的插入或删除操作都颇具效率,但是随机访问操作则效率不高。(存放元素的内存不连续,因此不支持iterator的偏移运算)

③.deque:以连续内存来存放元素,与vector类似,但同时对于最前端和最后端元素的插入、删除操作效率更高。

3.定义顺序性容器方法:

①.产生空容器:

list<string> slist;
vector<string> ivec;

②.产生特定大小的容器,每个元素都以其默认值作为初值。(eg.int和double类型的默认值为0)

vector<int> ivec(10);
list<string> ilist(20);

③.产生特定大小的容器,并为每个元素指定初值。

vector<int> ivec(1024,10);
list<double> ilist(10,5.20);

④.通过一对iterator产生容器。这对iterator用来标示一整组作为初值的元素的范围。

int ia[5] = {1,2,3,4,5};
vector<int> ivec(ia,ia+5);
list<int> ilist(ia,ia+5);

⑤.根据某个容器产出新容器。复制原容器内的元素,作为新容器的初值。

list<string> ilist1;
list<string> ilist2(ilist1);

4.三种顺序性容器都有push_back()和pop_back()函数,但只有list和deque容器拥有push_front()和pop_front()函数。

5.insert函数的变形函数(除push_front()和push_back()外)

①.

iterator insert(ierator position,elemType value);

将value值插入position之前,同时会返回一个iterator指向被插入的元素。

②.

void insert(iterator position,int count,elemType value);

在position前插入count个元素,这些元素的值都和value的相同。

③.

void insert(iterator position,iterator2 first,iterator2 last);

可在position之前插入[first,last)所标示的各个元素。

④.

iterator insert(iterator position);

在position之前插入元素,元素的初值为其所属属性的默认值。

6.erase()函数的变形函数(除pop_front()和pop_back()外)

①.

iterator erase(iterator position);

删除position所指的元素。

②.

iterator erase(iterator first,iterator last);

删除[first,last)范围内的元素。

五.使用泛型算法

1.使用泛型算法需要包含对应的头文件"algorithm";

#include<algorithm>

2.常用泛型搜索算法:

①.find()用于搜索无序集合中是否存在某值。搜索范围由iterator[first,last)标出。如果找到目标, find()会返回一个iterator指向该值,否则返回一个iterator指向last。

iterator find(iterator first, iterator last, elemType value);

②.binary_search()用于有序集合的搜索。如果搜索到目标则返回true,否则返回false。binary_search比find()更有效率。

bool binary_search(containerType<elemType> name, elemType value);

③.count()返回数值相符的元素数目。

④.search()比对某个容器内是否存在某个子序列。例如给定序列{1,3,5,7,2,9},如果搜索子序列{5,7,2},则search()会返回一个iterator指向子序列起始处。如果子序列不存在,就返回一个iterator指向容器末尾

3.取得数列最大元素值:max_element()。将一对iterator传给max_element(),它会返回该范围内的最大值。

elemType max_element(iterator first,iterator last);

4.复制容器:copy()。将一对iterator传给copy()标示出复制范围,第三个iterator指向复制行为的目的地。

void copy(iterator1 first,iterator1 last,iterator2 begin);

六.设计泛型算法

泛型算法filiter()的C++代码:

#include<iostream>
//#include<fuctional> //使用function objectL less<int>
#include<vector>
#include<algorithm> ///使用泛型算法find_if()
using namespace std;


template<typename InputIterator, typename OutputIterator, typename ElemType, typename comp>
OutputIterator filter(InputIterator first, InputIterator last, OutputIterator at, const ElemType& value, comp pred) //参数分别为传入容器的范围,传入容器的首地址,用于比较的值,比较类型函数
{
	while ((first = find_if(first, last, bind2nd(pred, value))) != last)
	{
		cout << "found value: " << *first << endl;
		//将过滤后的数据放到新的容器,同时更新相应位置:
		*at++ = *first++;
	}
}

int main()
{
	const int elem_size = 8;
	int is[ elem_size ] = { 12,8,43,0,66,21,3,7 };
	vector<int> ivec(elem_size);
	cout << "过滤数组中小于8的值:" << endl;
	filter(is, is + elem_size, ivec.begin(), elem_size,less<int>());


	system("pause");
	return 0;
}

知识点:

1.若要使用事先定义的function object,需包含头文件:#inclucde<funcitional>

(visual studio 2022中已无法打开源文件<fuctional>)

其中包括:

①.六个算术运算:plus<type>,minus<type>,multiplies<type>,divides<type>,negate<type>,modules<type>。

②.六个关系运算:less<type>,less_equal<type>,greater<type>,greater_equal<type>,equal_to<type>,not_equal_to<type>。

③.三个逻辑运算,分别对应&&、||、!:logical_and<type>,logical_or<type>,logical_not<type>。

2.适配器adapter:

①.binder adapter:使binary(二元)fuction object转化为unary(一元)fuction object。

(1).bind1st:将指定值绑定至第一操作数。

bind1st(less<int>,val);
//相当于: val<

(2).bind2nd:将指定值绑定至第二操作数。

bind2nd(less<int>,val);
//相当于 <val

②.negator adapter:对function object的真伪值取反。

(1).not1可对unary function object的真伪值取反。

not1(bind2nd(less<int>,value));
//小于取反得到大于或等于

(2).not2可对binary function object的真伪值取反。

③.insertion adapter: 使用需要包含头文件<iterator>

不能在array上使用,因为array不支持元素插入操作

可以对为设置大小的容器进行插入操作,但不能进行赋值操作

(1).back_inserter()会以容器的push_back()函数取代assignment运算符,参数为复制的目标容器。

(2).inserter()会以容器的insert()函数取代assignment运算符,接受两个参数,一个是复制的目标容器,另外一个是iterator指向容器内的插入操作起点。

(3).front_inserter()会以容器的push_front()函数取代assignment运算符,参数为复制的目标容器。同时这个inserter只适用于list和deque。

filter(ivec.begin(),ivec.end(),back_inserter(ivec2),elem_size,greater<int>);
//第三个参数从最初的ivec2变为了back_inserter(ivec2)
//此操作使push_back()函数替代assignment运算符将元素复制到ivec2容器中

七.map和set

1.使用map和set分别需要包含头文件<map>和 <set>。

2.使用map:

(1).map被定义为一对数值:

map<key,value> mapname;

其中的key通常是个字符串,扮演索引的角色,value则是key对应的值。

(2).map有两个member,分别为first指向key,second指向value:

 map<string,int> m1;
 map<string,int>::const_iterator it = m1.begin();
 it->first; //key
 it->second; //value

(3).查询某个map内是否存在某个key:

①.把key当作索引使用:

int count = 0 ;
if(!(count = words["vermeer"]));

原理:若map中不存在某个key,则会将此key放到map中并获得默认值0。

②.通过map的find()函数:

map<string,int>::iterator::it = words.find("vermeer");

原理:如果key在map中,则会返回一个iterator指向key/map形成的一个pair,如果key不在map中则会返回end()。

③.通过map的count()函数:

if(words.count("vermeer"));

原理:count()函数返回key项在map内的个数。

3.使用set

(1).set由一群key组合而成:

set<string> iset;

(2).set的insert()函数:

①加入单一元素:使用单一参数的insert():

iset.insert(ival);

②加入某个范围的元素,使用双参数的insert():

iset.insert(vec.begin(),vec.end());

(3).set元素皆依据其所属类型默认的less-than(递增)运算符进行排列。

4.任何一个key在map和set中最多只会有一份,如果需要储存多份相同的key值,则必须使用multimap和multiset。

八.使用iostream iterator

#include<iostream>
#include<iterator> //istream_iterator, ostream_iterator
#include<algorithm> //copy(),sort()
#include<vector>
#include<string>
using namespace std;

int main()
{
	istream_iterator<string> is(cin); //first
	istream_iterator<string> eof; //end

	vector<string> text;
	//输入:
	cout << "输入:" << endl;
	copy(is, eof, back_inserter(text));

	sort(text.begin(), text.end());

	ostream_iterator<string> os(cout, " ");
	//输出:
	cout << "输出:" << endl;
	copy(text.begin(), text.end(), os);

	system("pause");
	return 0;
}

知识点:

1.包含头文件<iterator>使用iostream iterator类 -- istream_iterator和ostream_iterator,分别支持单一类型的元素读取和写入。

2.需要提供一对iterator:first和last用来表示元素范围:

指定istream对象即为first

不指定istream对象即为end-of-file

istream_iterator<string> is(cin); --- first; //指定istream对象即为first
istream_iterator<string> eof; --- last; //不指定istream对象即为end-of-file

3.创建ostream_iterator来标示字符串元素的输出位置:

ostream_iterator<string> os(cout," "):

第二个参数可以是C-style字符串,也可以是字符串常量,用来表示各个元素被输出时之间的分隔符。

4.使用copy()来进行输入和输出:

输入:

copy(is,eof,back_inserter(text));

输出:

copy(text.begin(),text.end(),os)

5.使用iostream_iterator完成从文件中读取,写到文件中去:

将istream_iterator绑定至ifstream object,并将ostream_iterator绑定至ofstream object。

ifstream in_file("input_file.txt");
ofstream out_file("output_file.txt");

istream_iterator<string> is(in_file); //first;
istream_iterator<string> eof; // last;

ostream_iterator<string> os(out_file," ");

最后

以上就是强健小蝴蝶为你收集整理的泛型编程风格的全部内容,希望文章能够帮你解决泛型编程风格所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部