[GeekBand] STL与泛型编程(1)

在C++语法的学习过程中,我们已经对模板有了基本的了解。泛型编程就是以模板为工具的、泛化的编程思想。本篇文章介绍了一些在之前的文章中没有涉及到的一些模板知识、泛型编程知识和几种容器。关于模板的一些重复知识在这里就不再进行赘述。

一、关于模板的知识点补充

?

1. 函数模板的参数推导与显式指定

通常情况下,我们一般采用参数的自动推导方式去使用函数模板。在自动推导时,为了确保推导的正确性,C++不允许任何形式的隐式类型转换。

这个限制就导致了如下的情况:


template
<class T>

int max(const T &a,const T &b)

{

????return a>b?a:b;

}

如果按照自动推导的方式,想要对1和2.0(int型和double型)进行比较,编译器是做不到的。为了解决这一问题,有如下两种方案:

第一种方案是显式进行类型转换。即max(double(1),2.0 );

第二种方案是采用显式指定模板的实例化,可采用这种语法:max<double>(1,2.0);

2. 模板的调用与匹配

当涉及到重载和模板共存时,编译器采用如下的顺序进行调用:

非模板重载函数 > 模板 > 进行隐式类型转换后再调用非模板重载函数。

当我们想强制调用模板函数时,可以使用如下的语法:

????Function_name <> (a,b);

利用一对尖括号表示要求调用模板方法。

3. 模板头中的常量使用

考虑如下的模板头:


template<typename T =
int, size_t r =
1024>

其中的第二模板参数为一个size_t类型(其本质为int类型)的常量,在模板类中的使用可以理解成是一个宏定义。

这种写法的好处在于,例如,你在这个模板类中定义了一个大小为r的缓冲区并对其进行操作。

如果这里r不是模板参数,则由于普通的数组大小定义只能是固定的,只能够申请动态数组。然而如果使用了数字作为模板参数,则相当于在实例化的时候,r对于这个模板就是一个常量,因此可以写出类似于int a[r]之类的语句。

另外,这里还涉及到了模板实参的默认值。注意,无论是类型名还是模板常量,均可以设置默认值。

?

二、泛型编程基础知识

?

1. Traits(特性)

????Traits通常以一种抽象类的形式存在,用于提取出不同类型变量的共同特点。然后将这种特点应用到运算之中。

????首先考虑如下求和函数:


template<typename T>

T Sigma(const T* const a,int n)

{

????int rlt =
0;

????for(i=0;i<n;i++)

????????rlt += a[i];

}

????表面上看,这个求和函数不存在什么问题,然而,当我们将这一求和函数应用到这样的场景时:


char a[10]
=
"zzzzzzzz";

cout << Sigma(a,10);

结果却不是‘z‘对应的ASCII的9倍,而小于这个值。其原因在于,char类型的变量只能表示0~255之间的数字,当结果大于255时,发生了数据溢出。显然,这不是我们在求和的过程中希望看到的结果。Char,short求和的返回类型至少应该是int,float返回类型应该是double,int返回类型应该是long……

对于这个函数来说,所谓的"特性"就是他们的数值属性,将这个属性提取出来,可以采用模板的特化的办法:


template
<typename T>
class Sigmatraits {};

template
<>
class Sigmatraits<char>{

????public:
typedef
int ReturnType

}

template
<>
class Sigmatraits<short>{

????public:
typedef
int ReturnType

}

//新的Sigma的定义

typename Sigmatraits<T>::ReturnType

Sigma(const T *
const a,int n)

{

typedef
typename Sigmatraits<T>::ReturnType ReturnType;

ReturnType S = ReturnType ();

for(int i=0;i<n;i++)

???? S+=a[i];

return S;

}

注意新的Sigma的定义中,typename Sigmatraits<T>::ReturnType 是返回值的类型。

?

????这里需要解释一下上面的返回值类型中,typename关键字的作用。

????在作为模板参数时,typename和class关键字的作用是完全相同的,当typename不作为class的同义字使用时,考虑如下代码:


struct A{

????typedef
int bar;

}

template<class T>

void foo(const T & t)

{

????T::bar *p; //这里是定义了一个p?还是T::bar作为一个变量乘以p?

}

int main()

{

????A x;

????foo(x);

}

上述代码看似没有什么问题,但是实际上是无法编译通过的。这涉及到了函数模板的二次编译。第一次编译时,对于函数模板foo,编译器不知道T::bar是一个什么东西。究竟是一个变量名,还是一个类型名?对于这种情况,C++规定默认情况下,class::member 表示一个成员变量,因此对于foo函数,则产生了"使用了未定义的变量p"的错误。如果要求member表示一个类型名,则必须显式地声明其为typename类型,即:


void foo(const T & t)

{

????typename T::bar *p; //通过编译

}

2. 迭代器——指针的泛化

????在之前C++的学习中,已经对迭代器进行了一个初步的介绍,迭代器的使用方法与指针类似。

  • 迭代器是容器和算法的接口,算法通常要以迭代器作为参数。
  • 迭代器使算法和容器分离开,使算法不再依赖于数据结构(容器)。
  • 迭代器又使算法和容器粘合在一起,使算法能够应用于不同的容器。

对于一般的STL迭代器,有以下的方法:


*iter


?存取实际元素


iter->member


?读取实际元素的成员


++iter


?向前步进,传回新位置


iter++


?向前步进,传回旧位置


--iter


?退步(传回新位置)


iter--


?退步(传回旧位置)


iter1== iter2


?判断两个迭代器是否相等


TYPE(iter)


?复制迭代器(copy构造函数)


TYPE()


?产生迭代器(default构造函数)


iter1=iter2


?赋值

另外,对于可以随机存取的数据结构,其还具有如下随机存取操作:


iter[n] ?


取索引位置为n的元素


iter += n


?向前跳n个元素


iter -= n ?


向后跳n个元素


iter + n ?


传回iter之后的第n个元素


n + iter ?


传回iter之后的第n个元素


iter - n ?


传回iter之前的第n个元素


iter1 - iter2 ?


传回iter1和iter2之间的距离


iter1 < iter2 ?


判断iter1是否在iter2之前


iter1 > iter2 ?


判断iter1是否在iter2之后


iter1 <= iter2


判断iter1是否不在iter2之后


iter1 >= iter2


判断iter1是否不在iter2之前

时间: 2024-08-29 02:24:41

[GeekBand] STL与泛型编程(1)的相关文章

[GeekBand] STL与泛型编程(2)

本篇文章在上一篇文章的基础上进一步介绍一些常用的容器. 一. Stack和Queue ? 二. Map Map是一种关联容器,存储的对象是键值(Key-Value)对.和Python中的字典相似.Map中的键值对永远是排好序的. Map中所存储的键对象必须是可排序的,默认采用从小到大的排序方式.也可以通过函数对象的方式进行指定.Map的标准头为: template <class _Kty, class _Ty,class _Pr = less<_Kty>,class _Alloc = a

[GeekBand] STL与泛型编程(3)

本篇文章主要介绍泛型算法中的变易.排序.数值算法. 一. 变易算法 所谓变易算法是指那些改变容器中的对象的操作. 1.1 copy组 template <class InputIterator, class OutputIterator> OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result); Copy操作是将两个输入迭代器之间的元素拷贝到输出迭代器处.注意拷贝时采用的是左对齐,

[GeekBand] STL 仿函数入门详解

本文参考文献::GeekBand课堂内容,授课老师:张文杰 :C++ Primer 11 中文版(第五版) page 37 :网络资料: 叶卡同学的部落格  http://www.leavesite.com/ 前言:本文主要通过关联容器set解释下仿函数的实现及工作原理. 一.STL六大组件简介 1.Containers(容器):各种数据结构,如Vector,List,Deque,Set,Map,用来存放数据2.Algorithms(算法):如. Sort,Search.3.Iterators(

学习BoolanC++笔记_01(STL与泛型编程第六周)

作者: ayaoko 出处: http://www.cnblogs.com/fyc006/> 关于作者:小可才疏学浅还请多多赐教! 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件([email protected])咨询. 1,你应具备的基础 C++基本语法(包括如何正确使用模板,templates)  2,我们的目标 C++标准库,了解,深入,良好使用,扩展 THE C++ STANDARD LIBRARY 作者:

Boolan C++ STL与泛型编程 二

本周主要是讲解了容器list的使用 List是一种可在常数时间内在任何位置执行插入和删除操作的顺序容器.list是双向链表,其迭代器是双向的.与其他顺序容器(array, vector, deque)相比,list容器在任意位置执行插入.提取.和移动元素的操作更高效,但它不能通过在容器中的位置直接获取元素. list主要拥有这些功能 c.rbegin()      返回逆向链表的第一个元素,即c链表的最后一个数据. c.rend()      返回逆向链表的最后一个元素的下一个位置,即c链表的第

C++ STL泛型编程——在ACM中的运用

学习过C++的朋友们应该对STL和泛型编程这两个名词不会陌生.两者之间的关系不言而喻,泛型编程的思想促使了STL的诞生,而STL则很好地体现了泛型编程这种思想.这次想简单说一下STL在ACM中的一些应用.我们知道,在ACM竞赛中,经常需要用到数组.字符串.队列.堆栈.链表等数据结构和排序.搜索等算法,以提高程序的时间.空间运行效率.然而如果这些数据结构总是需要手工来编写,那无疑会是一件很麻烦的工作,而STL的出现很好地解决了这个问题. 我们简单来了解一下STL.STL提供了三种类型的组件:容器.

STL之父Stepanov谈泛型编程的发展史

这是一篇Dr. Dobb's Journal对STL之父stepanov的采访.文中数次提到STL的基本思想.语言的特性.编程的一些根本问题等,非常精彩.这篇文章让我想去拜读下stepanov的大作<Elements of Programming>了.原文链接: http://www.stepanovpapers.com/drdobbs-interview.html 我先对文章内容做下总结,并在最后附上原文,把一些认为重要又精彩的语句进行了标红. Stepanov讲到其关于“泛型编程”(gen

&lt;&lt;C++标准程序库&gt;&gt;中的STL简单学习笔记

0. 内容为个人学习笔记, 仅供参考, 如有错漏, 欢迎指正! 1. STL中的所有组件都是由模板构成的, 所以其元素可以是任意型别的. 组件有: - 容器: 管理某类对象的集合. 不同的容器有各自的优缺点. - 迭代器: 用来在一个对象集群(Collection of Objects) 的元素上进行遍历. 这个CoB可以是容器/容器的一部分. 每种容器都提供了自己的迭代器. - 算法(Algorithm): 用来处理集群内的元素(比如: 查询,修改,排序等). - 适配器(adapter) -

STL之序列容器deque

首先看看deque的模板声明: template <class T,  class Alloc = allocator<T>>  // 原本还有个参数BufSize,现在新版本内置了,不允许用户指定了. class deque { //… protected: // 数据成员 iterator start; // 表现第一个节点 iterator finish; // 表现最后一个节点 map_pointer map; // 指向map, map是块连续空间,其内的每个元素都是一个