C++提高编程-泛型编程及STL(上)

c++提高编程(上)

本章主要讨论c++泛型编程 和 stl 技术
————————————————————

文章目录

产出:

1.模板

1.1.模板

c++除了面向对象思想,还有种编程思想,泛型编程。
而泛型编程主要是依靠模板来实现。

模板,建立通用的模具,大大提高复用性。
但也有其不能及,例如,模板不能直接使用,本质只是框架。
模板并不是通用的

1自动类型推导
2显示指定类型

//函数模板的注意事项
#include<iostream>
using namespace std;

template<class T>
void myChange(T &a,T &b){
   
	T temp = a;
	a = b;
	b = temp;
};
//myFun01()错误,因为没有确认S的数据类型
//myFun01<int>()正确
template<class S>
void myFun01(){
   
	
};


void intChange(int &a,int &b){
   
	int temp = a;
	a = b;
	b = temp;

};
void doubleChange(double &a,double &b){
   
	double temp = a;
	a = b;
	b = temp;

};

int main(){
   
	int a = 10;
	int b = 20;
	double c = 30.5;
	double d = 40.6;
	//intChange(a,b);
	myChange(a,b);//自动类型推导
	//注意事项,1.模板函数体中必须使用到 通用数据类型T,否则报错。
	//即 必须确定 T 的数据类型。才能使用

	// 必须推导出一致的数据类型才可,例如传入参数 不是int,则报错

	myChange<int>(a,b);//显示指定类型
	cout<<a<<endl;
	cout<<b<<endl;
	system("pause");
	return 0;
}

——————————————————————

1.2、函数模板案例

(将不同数据类型的数组由大到小排序)

//将两个测试函数test01,test02模块化的时候,运行结果不对。
//分析应该是sizeof(T)写法不对,对的话结果肯定是对的,希望有老板看到帮解决下哈哈哈我就下搁置了
错的地方备注了

#include<iostream>
using namespace std;
template<class T>
void change(T&a,T&b ){
   
	T temp = a;
	a = b;
	b = temp;
};

template<class T>
void mySort(T Array[],int len){
   
	for(int i=0;i <len;i++){
   
		int Max = i;//定义最大数下标
		for(int j=i+1;j<len;j++){
   
			if (Array[Max] < Array[j]){
   
				Max = j;//更新最大数下标

			};
		};
		if(Max != i){
   
			change(Array[Max],Array[i]);
		};
	};
};
template<class T>
void outArray(T array[],int len){
   
	for(int i=0;i<len;i++){
   
		cout<<array[i]<<" ";
	};
	cout<<endl;
};
void test01(){
   
	char array01[] = "acegik";
	int len = sizeof(array01)/sizeof(char);
	outArray(array01,len);
	mySort(array01,len);
	outArray(array01,len);
};
void test02(){
   
	int array02[] = {
   1,3,5,7,9};
	int len = sizeof(array02)/sizeof(int);
	outArray(array02,len);
	mySort(array02,len);
	outArray(array02,len);
};
//
//template<class T>
//void test(T array01[]){
   
//	int len01 = 6;
//	outArray(array01,len01);
//	mySort(array01,len01);
//	outArray(array01,len01);
//};

int main(){
   
	/*char array01[] = "acegik"; 
	int array02[] = {1,3,5,7,9};*/

	test01();
	test02();

	/*test(array01);
	test(array02);*/

	system("pause");
	return 0;
}

1.3、普通函数与函数模板区别

普通函数可以直接发生 自动类型转换(隐式类型转换)

函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
如果利用显示指定类型,可以发生隐式类型转换
所以建议使用显示指定类型的方式调用函数模板 直接自己确定好。

1.4、普通函数与函数模板调用规则

1.如果普通函数和函数模板同时存在,优先调用普通模板
2.可以通过空模板参数列表来强制调用函数模板
也可以在添加参数

3.函数模板可以发生重载
4.如果函数模板可以产生更好的匹配,优先调用函数模板。

#include<iostream>
using namespace std;

void change(int a,int b){
   
	cout<<"普通函数"<<endl;
};
template<class T>
void change(T a,T b){
   
	cout<<"函数模板"<<endl;;
};
void test01(){
   
	int a = 10;
	int b = 20;
	change<int>(a,b);
}
int main(){
   
	test01();
	system("pause");
	return 0;
}

1.5、模板局限性

模板并不是万能的,特定数据类型,需要用具体化方式做特殊实现。


//模板局限性   例如下面案例 比大小,自定义的数据类型就不可以。需要重载模板版本

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

class Person{
   
public:
	Person(string name,int age){
   
		this->name = name;
		this->age = age;
	};
	string name;
	int age;
};
template<class T>
bool IsSame(T a,T b){
   
	if(a == b){
   
		return true;
	}else{
   
		return false;
	}
};
void test01(){
   
	int a = 10;
	int b = 10;
	bool end = IsSame(a,b);
	if (end==true){
   
		cout<<"相同"<<endl;
	}else{
   
		cout<<"不相同"<<endl;
	}
};
//提供模板重载版本,原模板无法判断自定义数据类型
template<>bool IsSame(Person a,Person b){
   
	if(a.name == b.name){
   
		return true;
	}else{
   
		return false;
	};
};
void test02(){
   
	Person p1("毕羽",22);
	Person p2("毕羽",22);
	bool end = IsSame(p1,p2);
	if (end==true){
   
		cout<<"相同"<<endl;
	}else{
   
		cout<<"不相同"<<endl;
	}
}
int main(){
   
	test02();
	system("pause");
	return 0;
}

1.6、类模板

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

template<class A,class B = int>
class Person{
   
public:
	Person(A name,B age){
   
		this->name = name;
		this->age = age;
	};
	void show(){
   
		cout<<this->name<<":"<<this->age<<endl;
	};
	string name;
	int age;
};
int main(){
   
	//类模板使用的时候只能使用 显示指定类型,不可以使用自动类型推导
	Person<string,int>p1("毕羽",22);
	p1.show();

	//类模板中的模板参数列表,可以指定默认类型
	Person<string>p2("陈曦",20);
	p2.show();

	system("pause");
	return 0;
}

类模板中的成员函数 并不是一开始就创建的,而是被调用时被创建

//类模板中的成员函数 并不是一开始就创建的,而是被调用时被创建

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

class Person01{
   
public:
	void show01(){
   
		cout<<"showPerson01"<<endl;
	}
	string name;
	int age;
};

class Person02{
   
public:
	void show02(){
   
		cout<<"showPerson02"<<endl;
	}
	string name;
	int age;
};

template<class T>
class Myclass{
   
public:
	T obj;
	void fun01(){
   
		obj.show01();
	};
	void fun02(){
   
		obj.show02();
	};
};
void test01(){
   
	Myclass<Person01>m1;
	m1.fun01();
	Myclass<Person02>m2;
	m2.fun02();
};

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

1.7、类模板实例化的对象 向函数中传参

三种方式
1.指定传入类型(最为常用,阿牛我喜欢用这个)
2.参数模板化
3.整个类模板化

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

template<class T1,class T2>
class Person{
   
public:
	Person(T1 name,T2 age){
   
		this->name = name;
		this->age = age;
	}
	T1 name;
	T2 age;
	void show(){
   
		cout<<this->name<<"-"<<this->age<<endl;
	};
};
//指定传入类型
//void fun00(Person<string,int>&p1){
   
//	p1.show();
//};
//参数模板化
//template<class T1,class T2>
//void fun00(Person<T1,T2>p1){
   
//	p1.show();
//};

//整个类模板化
template<class T>
void fun00(T p1){
   
	p1.show();
	cout<<typeid(T).name()<<endl;
};

int main(){
   
	Person<string,int>p1("阿牛",20);
	fun00(p1);
	system("pause");
	return 0;
}

1.8、类模板与继承

两点,1 、父类如果是类模板,子类需要指明父类模板参数才可以实例化对象

2、类模板的子类如果想灵活些,很简单,那就变成类模板

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

template<class T1>
class Person{
   
public:
	T1 obj;
};
//指明父类的模板参数类型才可以实例化对象
class Son1 : public Person<int>{
   
	
};
//或者也变成类模板
template<class T1,class T2>
class Son2 : public Person<T2>{
   
public:
	Son2(){
   
		cout<<typeid(T1).name()<<endl;
		cout<<typeid(T2).name()<<endl;
	}
	T1 obj;
};
void test01(){
   
	Son2<string,int>s2;
};
int main(){
   
	test01();
	system("pause");
	return 0;
}

1.9、类模板的类外实现

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

template<class T1>
class Person{
   
public:
	Person(T1 age);/*{
		this->age = age;
	};*/
	void fun01();/*{
		cout<<"___"<<endl;
	};*/
	int age;
};
template<class T1>
Person<T1>::Person(T1 age){
   
	this->age = age;
};
template<class T1>
void Person<T1>::fun01(){
   
	cout<<"___"<<endl;
};
void test01(){
   
	Person<int> p1(10);
	p1.fun01();
};
int main(){
   
	test01();
	system("pause");
	return 0;
}

1.10、类模板份文件编写

————————————————

2、STL

2.1、SLT基本概念1

之前学过的面向对象思想(封装,继承,多态)
封装:例如类,把事物的相同属性和行为抽象出来。
继承:派生类继承基类的属性和行为
多态:父类指针指向子类对象,实现多种形态。
其目的 主要还是 提升代码复用性

之前的泛型编程思想(模板),其目的也是复用性的提升
但是相同的问题,可以采用不同的算法和数据结构区解决。人与人之间不会一直统一,这种程度上 增加了代码的重复性(因为达到的目的都是一样的)。
为了建立数据结构和算法的一套标准,诞生了STL。

SLT广义上 分为
容器:各种数据结构:vector,deque,list,set,map
算法:常用算法,sort,for_each,copy,find.
迭代器:目前阶段可以理解为指针,是容器和算法的粘合剂,写好的算法需要通过迭代器来控制容器。

2.2、STL基本概念2

standard template librairy
容器(container),
算法(algorithm),
迭代器(iterator),
仿函数,行为类似函数,可作为算法的某种策略
适配器,用于容器,迭代器,仿函数 这些接口的修饰
空间配置器:用于空间的配置和管理

STL容器
就是 将 运用最广泛的数据结构实现出来。长荣的数据结构:数组,链表,栈,树,集合,映射,队列等。
这些容器 分为 序列式容器和关系式容器
序列式容器:值的排序,容器中每个元素均有固定的位置。
关系式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系。
————————————————
算法
有限的步骤,解决逻辑或数学上的问题。
质变算法和非质变算法

质变算法:运算过程中会改变区间中的元素,例如拷贝,添加,删除等
非质变算法反之,例如查找,计数,遍历,寻找极值等。
—————————————————
迭代器:目前阶段可以理解为指针,是容器和算法的粘合剂,写好的算法需要通过迭代器来控制容器。
每个容器都有自己的专属迭代器

输入迭代器,输出迭代器,前向迭代器,双向迭代器,随机访问迭代器。
(只读) (只写)

2.3 vector容器

vector容器的数据结构和数组非常相似,也称为单端数组
不同之处是数组是静态的,一经定义就不可以拓展,而vector可以动态扩展

其动态扩展并不是在原有空间后扩展,因为无法确定这之后的内存空间是否被使用。所以另找一块更大的内存空间,将原数据拷贝到新空间,释放原k空间

		   ———————————— push_back()
		   |
		   |
		   |
		   |  front();						back()
	 	   ————————————pop_back();

v.rend() v.begin() v.rbegin() v.end() 迭代器
头之前 头 尾 尾之后
insert()

2.3.1、vector容器 三种遍历

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

void fun01(int QQ){
   
	cout<<QQ<<endl;
};
int main(){
   
	vector<int>v1;
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	v1.push_back(40);

	//while遍历
	vector<int>::iterator v1_s = v1.begin();
	vector<int>::iterator v2_e = v1.end();
	while(v1_s != v2_e){
   
		cout<<*v1_s;
		v1_s++;
	};
	cout<<endl;

	//for循环遍历
	for(vector<int>::iterator Xi = v1.begin();Xi != v1.end();Xi++){
   
		cout<<*Xi;
	};
	cout<<endl;
	/*STL提供的遍历*/

	for_each(v1.begin(),v1.end(),fun01);

	system("pause");
	return 0;
}

2.3.2、vector容器存放自定义数据类型

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

class Person{
   
public:
	Person(string name,int age){
   
		this->name = name;
		this->age = age;
	};
	string name;
	int age;
};
void test01(){
   
	vector<Person>v;
	Person p1("aaa",01);
	Person p2("bbb",02);
	Person p3("ccc",03);
	Person p4("ddd",04);
	Person p5("eee",05);

	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);

	for(vector<Person>::iterator v2 = v.begin();v2 != v.end();v2++){
   
		cout<<(*v2).name<<endl;
		cout<<v2->age<<endl;
	};
	cout<<"---------------"<<endl;
};

void test02(){
   
	vector<Person*>v5;
	Person p1("aaa",01);
	Person p2("bbb",02);
	Person p3("ccc",03);
	Person p4("ddd",04);
	Person p5("eee",05);

	v5.push_back(&p1);
	v5.push_back(&p2);
	v5.push_back(&p3);
	v5.push_back(&p4);
	v5.push_back(&p5);

	for(vector<Person*>::iterator v6 = v5.begin();v6!=v5.end();v6++){
   
		cout<<(*v6)->name<<endl;
		cout<<(*v6)->age<<endl;
	};

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

2.3.3、vector容器嵌套

俄罗斯套娃,大vector套5个小vector。
for循环中,<&g

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值