STL泛型编程

1.C++模板简介
2.泛型编程
3.容器
4.进阶

1.模板
C++函数模板,类模板,操作符重载
模板是一种特性,允许函数或类通过泛型的形式表现或运行
可以使得函数或类在对应不同的型别的时候正常工作,而无需为每一个类型都写一份代码,泛型的typename
template<typename T>T Max(T a,T b)
{
return(a>b)?a:b;
}
class template:使用泛型参数的类
Function template:使用泛型参数的类
模板实例化
模板的声明:并未给出一个完全的定义,只是提供了一个函数或类的语法框架
实例化的过程指从模板构造出一个真正的函数或类的过程
template<typename T>struct Object{}
显示实例化
隐式实例化
函数模板:参数化的一族函数,通过模板可以定义一系列函数
template<typename T>
inline T Max
{
const T& a,
const T& b,
}
也可以用class来代替typename来定义类别参数
函数模板的使用
编译器在编译时已经知道MAX函数需要传递的型别
函数模板:模板参数是由传递给模板函数的实参决定的
Max(1,2)
用static_cast或强制转换参数型别以使两者匹配
Max(static_cast<double>(1),2.0)
显示指定T的类别
Max<double>(1,2.0)
函数模板的重载
inline int const& Max(const int const& a,const int const& b);

template<typename T>
inline T const& Max(const T& a,const T const& b)

template<typename T>
inline T const& Max(const T const& a,const T const& b,const T const& c)
其他因素都相同的情况下,重载函数过程调用非模板函数,而不是模板产生实例
对于不同的实参型别,模板函数定义了一族函数
当传递模板实参的时候,函数模板依据实参的类型进行实例化
可以显示指定模板的实参类型
函数模板可以重载
当函数重载模板时,将改变限制在显示指定模板参数
所有的重载版本的声明必须位于他们被调用位置之前
C++类模板
通过参数泛化,构建出一族不同类别的类实例
类模板实参可以是某一型别或常量
类模板声明与函数模板类似
在类模板内部,T可以像其他类别一样,定义成员变量和成员函数
要定义一个类模板的成员函数,则要指明一个模板类
类模板的实现
使用类模板
Stack<int> stack:定义了一个型别为int的stack
Stack<int,100>stack定义了一个型别为int,大小为100的Stack
Stack<Stack<int>> intStack
类模板的特化specializations
允许对一个类模板的某些模板参数类型做特化
好处在于:对于某冲特殊的型别,可能可以做些特别的优化或提供不同的实现方式
std::vector<T>m_Member;
std::size_t m_nMaxSize=n
特化一个类模板的时候也意味着需要特化所有参数化的成员函数
2.泛型编程
概念,关联特性,迭代器
泛型编程是一种方法,稍微具体化的方式给出
不依赖于具体的语言
通过模板以及相关性质实现
traits
调用构造函数时初始值为0
T total=T();
char szName[]="abc";
std::size_t nlength=strlen(szNames);
Char型最大的类型为255
int s=Sigma<int>(p,q)
为每一个Sigma函数的参数型别创建一种关联,关联的型别就是来存储Sigma的型别
Sigma函数返回值的型别叫做T的traits
Traits可以实现为模板类
association是针对每个具体型别T的特化
template<typename T> class SigamaTraits{};
template<>class SigamaTraits<char>{
public:typedef int ReturnType;
};
迭代器
泛化的指针:generalization of pointers
迭代器本身是一个对象,指向另外一个(可以被迭代的)对象
用来迭代一组对象,如果迭代器指向一组对象中的某个元素,则通过incerment以后他就可以指向这组对象中的下一个元素
在STL中迭代器最重要的思想是分离算法和容器
迭代器将算法和容器粘合(stick)在一起
find算法对于不同的容器都适用
std::vector<int> v();
std::list<int> I();
std::deque D();
(1)Vector
是一个能够存放任意型别的动态数组
数据结构和操作与数组类似,在内存中的表现形式是一段连续的地址空间
#include<vector>
int main()
{
std::vector v;
}
访问vector中的元素
调用vector::at(),调用vector::operator[]
at()进行边界检查
删除vector函数
clear清楚整个vector
pop_back:弹出vector尾部的元素
remove_if函数定义在algorithm中,需include<algorith>
v.erase(std::remove_if
(v.begin(),v.end(),ContainsString(L"C++")),
v.end();
Deque是一个能够存放任意型别的双向队列
Deque提供的函数与vector类似,新增了连个函数
push_front:在头部插入了一个元素
pop_front在头部弹出一个元素
Deque大块分配内存
List能够存放任意型别的双向链表
list可以随意插入和删除元素
只能以连续的方式存取List中的元素-查找任意元素的平均时间和List的长度成反比
4.STL整体结构
仿函数,适配器
STL整体结构
仿函数:作用相当于一个函数指针
std::remove_if(v.begin(),v.end(),ContainsStreing(L"C++"))
其实现是一个class,再以仿函数产生一个指针
仿函数与算法之间的关系
template <typename T> class Functor
{
void operator();
}
必须重载函数调用function call运算子operator()
set默认以less作为元素的排序行为,如果两个set具有不同的排序规则,那么对他们进行赋值或==判断会导致错误
仿函数适配器
将无法匹配的仿函数套接成可以匹配的型别
binder1st/binder2nd
nit_equal_to构造函数不接受参数0
not_equal_to的operator()不接受一个参数,需要两个参数
bool operator()(const_Ty& _Left,const _Ty& _Right) const
mem_fun/mem_fun_ref
(2)mem_fun/mem_fun_ref
用来适配对象的成员函数
f是全局函数f(obj)
f是obj的成员函数,obj非指针obj.f()
单线程情况下涉及对字符串的操作,首选std::string/std::wstring
多线程情况下需注意string是否带引用计数器
可考虑使用vector<char>/vector<wchar_t>替代
当new出对象并放入容器时,要在销毁容器前delete
尽量用算法代替手写循环
通过swap为容器缩水
stl容器装入的对象是原始对象的一个拷贝
如果对象很大,拷贝需要大量的性能开销
在有对象继承情况下,建立指针的容器而不是对象的容器
建立指针的容器而不是对象的容器
拷贝指针总是很快,开销小
不会产生slicing问题
(3)容器
序列式容器
stack是一种先进后出的数据结构,只有一个出口
只能访问Stack栈顶元素,不允许遍历
template<class_T>
stack的底层数据结构
以list作为Stack的底层数据结构
除了deque,还可以list作为数据结构
Queue是一种先进先出的数据结构
STL queue是以deque作为默认的底层结构
template<class_Ty,class_Container=deque<_Ty>>
可以看作是对deque的包装或者适配,它修改了deque的接口
并提供front()\back()\pop\push()接口
因为queue不允许遍历,故没有iterator
以list作为Stack的底层数据结构
关联式容器
元素与元素间具有某种联系
Map and Multimap
Map存储的对象是Key、Value pair
不允许有重复的key
map存储的对象必须具备可排序性
默认采用less定义排序行为
可以自定义排序行为(通过仿函数)
#include<map> std
Multimap允许有重复的key
Set也是一种关联容器,存储的对象本身是key又是Value
不允许有重复的Key
set存储的对象必须具有可排序性的
template<class_Kty,class_Pr=less<_Kity>,class_Alloc=allocator<_Kty>>
insert(Person(L"BILL",4));
std::set<Person,PersonldCompare>::iterator it=ps1.beging();
std::advance(it,1);
ps1.erase(it);
set_union以后是按章id排序的
set_intersection算法
set_difference(ps1.begin(),ps1.end(),ps3.begin(),ps3.end(),PersonldCompare());
根据给的参数的顺序,找setdifference的取反,该元素不包含在dest中
set需要特别注意的问题:
用于排序的成员不可改变
除了真正的key,其他成员可以改变但需要特殊手段
set的实现方式不允许通过迭代器改变对象的成员
真正参与排序的是ID
const_cast<Person&>(*it).SetName(L*"Bill Gates");改的不是临时对象,是set
Person tempCopy(*it);
tempCopy.SetName(L"BILL Gates");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值