假设有这样一种情况:某人将一车文件交给小王。倘若小王的抽屉是空的,那么小王从车上取出最上面的文件将其放入抽屉;倘若抽屉是满的,小王从抽屉中取出最上面的文件,放入垃圾篓;倘若抽屉即不空也未满,那么小王抛硬币随机决定是否从文件车拿一份文件放入自己的抽屉,还是从自己的抽屉取出最上面的文件,放入垃圾篓。

显而易见,小王的抽屉就类似一个Stack类。由于不知道存储文件的类型,使用模板来定义;定义如下:

在模板类的定义中,有以下知识点:

 1.条件编译#ifdef --- #endif的作用和使用技巧

作用:我们可以用它区隔一些与特定头文件、程序库和其他文件版本有关的代码。不用条件编译命令而直接用if语句也能达到要求,用条件编译命令有什么好处呢?的确,此问题完全可以不用条件编译处理,但那样做目标程序长(因为所有语句都编译),而采用条件编译,可以减少被编译的语句,从而减少目标的长度。当条件编译段比较多时,目标程序长度可以大大减少。

使用技巧和说明见地址:http://blog.csdn.net/qianhen123/article/details/36177337

 2.枚举常量类型的使用enum{empty,full,notfull,SIZE=10};

使用了空,满,未满三种状态,用作成员函数decision()对Stack存储状态的判断,此处定义为枚举常量,类似于将empty, full, notfull依次设置为0,1,2的静态int常量,SIZE为缺省定义的Stack空间大小

3.explicit关键字的使用

C++中,一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数),承担了两个角色。1 是个构造器,2 是个默认且隐含的类型转换操作符。所以, 有时候在我们写下如 AAA = XXX,这样的代码, 且恰好XXX的类型正好是AAA单参数构造器的参数类型,这时候编译器就自动调用这个构造器,创建一个AAA的对象。这样看起来好像很酷, 很方便。 但在某些情况下(见下面权威的例子),却违背了我们(程序员)的本意。这时候就要在这个构造器前面加上explicit修饰,指定这个构造器只能被明确的调用,使用,
不能作为类型转换操作符被隐含的使用。explicit构造函数是用来防止隐式转换的。请看下面的代码:

Test1的构造函数带一个int型的参数,代码17行会隐式转换成调用Test1的这个构造函数。而Test2的构造函数被声明为explicit(显式),这表示不能通过隐式转换来调用这个构造函数,因此代码18行会出现编译错误。普通构造函数能够被隐式调用。而explicit构造函数只能被显式调用。

4.模板声明的简写与否,即 Stack,Stack<type>的使用范围

         Stack是Stack<type>的缩写,但是只能在类中使用,即在类中说明参数类型或者模板函数返回类型的时候,用stack即可。但是,在类外,指定模板函数体返回类型,参数类型,使用作用域解析运算符时候,必须使用完整的Stack<type>。

5.引用的使用

         注意成员函数bool pop(type& temp);//元素自堆弹出,完成了两件事,第一是将Stack顶指针所指元素传递给引用temp,第二是返回了bool型变量说明是否元素弹出成功。即完成了两个元素的返回。基于不带引用和指针的参数的函数只能返回一个值,此种方法很有技巧。

6.赋值运算符“=”重载的注意    “Stack<type>& Stack<type>::operator=(const Stack<type>& temp)”

        即在使用对象之间的直接赋值的时候,应该考虑:第一当Stack对象是否自己给自己赋值,其次是否为空,不为空,应该先清空该Stack对象;

                if(this==&temp)//此处判读是否是自己给自己赋值 
                return *this;//注意this 为const Stack<type>*,temp为const Stack<type>&,而&temp才是指针
                delete []items;//清空当前stack,释放内存

       同时*this指针的返回以及重载函数的返回值类型为引用均为经典写法

回到该问题,主函数的定义如下:

其中in对应文件车,stack对应抽屉,out对应垃圾车。主要知识点为

7.srand(),time(),rand()的使用

       首先应该包含对应的库文件-----#include"cstdlib"//for rand(),srand()   #include"ctime"//for time()。函数原型如下:

int rand(void)------返回[0,RAND_MAX],其中RAND—MAX0x7fff

void srand(unsigned seed)-----参数seed是rand()的种子,用来初始化rand()的起始值

       函数rand()是真正的随机数生成器,而srand()会设置供rand()使用的随机数种子。系统在调用rand()之前都会自动调用srand(),如果用户在rand()之前曾调用过srand()给参数seed指定了一个值,那么
rand()就会将seed的值作为产生伪随机数(rand随机数的产生遵循一定策略,seed设定了,即可认为产生了一组数,每次取一个)的初始值;而如果用户在rand()前没有调用过srand(),那么系统默认将1作为伪随机数的初始值。seed一旦赋予定值,那么每次rand()产生的随机数序列都是一样的。例如:srand(1); 直接使用1来初始化种子,后面每次使rand()均返回相同的int值。如下所示代码片段。
结果如下,结果观察到同一种子数下伪随机数相同,不同种子数则不同
41
18467
41
18467
45
29216
45
29216
 为了防止随机数每次重复。常常使用如下三种方法:
             1.系统时间来初始化,即使用 time函数来获得系统时间。time()函数可以获取当前的系统时间,返回的结果是一个time_t类型,即一大整数,其值表示从CUT(CoordinatedUniversal Time)时间1970年1月1日00:00:00(称为UNIX系统的Epoch时间)到当前时刻的秒数,然后将time_t型数据转化为(unsigned)型再传给srand函数,即: srand((unsigned)time(&t)) ;
         2.不需要定义time_t型t变量,即:srand((unsigned) time(NULL)); 直接传入一个空指针。由于随机数种子随时间变化而变,故可以认为此种方法产生真正的随机数,本文中的随机决定就是采用此种方法。见主函数27行
         3.srand((int)getpid());使用程序的ID(getpid())来作为初始化种子,在同一个程序中这个种子是固定的。

C++之Stack模板类的更多相关文章

  1. 从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename

    一.缺省模板参数 回顾前面的文章,都是自己管理stack的内存,无论是链栈还是数组栈,能否借助标准模板容器管理呢?答案是肯定的,只需要多传一个模板参数即可,而且模板参数还可以是缺省的,如下: temp ...

  2. 缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename

    一.缺省模板参数 回顾前面的文章,都是自己管理stack的内存,无论是链栈还是数组栈,能否借助标准模板容器管理呢?答案是肯定的,只需要多传一个模板参数即可,而且模板参数还可以是缺省的,如下: temp ...

  3. C++模板类[初步]

    /* * stacktp.h * * Created on: 2014年3月29日 * Author: */ /** * - 模板类的概念,与使用 * -# export template <c ...

  4. 类模板、Stack的类模板实现(自定义链栈方式,自定义数组方式)

    一.类模板 类模板:将类定义中的数据类型参数化 类模板实际上是函数模板的推广,可以用相同的类模板来组建任意类型的对象集合 (一).类模板的定义 template  <类型形参表> clas ...

  5. C++:栈(stack)的模板类实现

    1.基本概念 栈中的元素遵守“先进后出”的原则(LIFO,Last In First Out) 只能在栈顶进行插入和删除操作 压栈(或推入.进栈)即push,将数据放入栈顶并将栈顶指针加一 出栈(或弹 ...

  6. C++ 模板函数与模板类

    一.模板函数 函数模板提供了一类函数的抽象,即代表了一类函数.当函数模板被实例化后,它会生成具体的模板函数.例如下面便是一个函数模板:

  7. C++模板类的使用

    1.定义模板类 通过类似于下面的语法可以定义一个模板类: template<typename T> class Job : public virtual RefBase { public: ...

  8. C++:类模板与模板类

    6.3 类模板和模板类 所谓类模板,实际上是建立一个通用类,其数据成员.成员函数的返回值类型和形参类型不具体指定,用一个虚拟的类型来代表.使用类模板定义对象时,系统会实参的类型来取代类模板中虚拟类型从 ...

  9. 使用模板类导致error LNK2019: 无法解析的外部符号

    原地址 1.定义模板类: template<class T> class Stack {....}; 2.定义模板成员函数: 每个函数头都要以相同的模板声明打头,并将类限定符改成:类名&l ...

随机推荐

  1. C#聚合运算方法

    Aggregate 对集合值执行自定义聚合运算 Average 计算集合平均值 Count 对集合的元素惊醒计数,还可以仅对满足某一谓词函数的元素进行计数 LongCount 对大型集合中的元素进行计 ...

  2. vim终端配色(非gui版本)——Monokai

    啥也别说,先上图. 具体配置: 1. 将molokai.vim文件(下面贴出)放到 ~/.vim/colors 目录下,如没有此文件夹需自行创建. 提示:~ 代表用户主目录,如我的用户名是 akaed ...

  3. <Linux内核源码>文件系统VFS内核4.0.4版本基本概念源码

    题外话:Linux内核从2.x和3.x到现在最新的4.x变化非常大,最直观的表现就是很多书上的内核代码已经无法直接继续使用,所以看看新的源码是非常有意义的! (下文中的内核源码都来自于 kernel ...

  4. java入门了解12

    1.SequenceInputStream序列流:能将其他输入流的串联 用处:读完第一个再去读第二个输入流 用法:构造方法:SequenceInputStream(InputStream s1,Inp ...

  5. java:Map借口及其子类HashMap四

    java:Map借口及其子类HashMap四 使用非系统对象作为key,使用匿名对象获取数据 在Map中可以使用匿名对象找到一个key对应的value. person: public class Ha ...

  6. C++中的右结合性

    看到网上的说是,右结合 但是还是从左往右算 // 以下说法是从网上看的,不知道对不 a ? b : c ? d : e 如何进行呢? 它的结合律是从右向左,所以它等效于 a ? b : ( c ? d ...

  7. Appium-关于appium的原生控件的 xpath 定位问题及常用方法

    最近遇到的项目,发现很多元素,都没有标明id.text.content-desc,classname中又有很多是相同,导致无法定位 第一,appium1.5及之后的版本废弃了name属性(如name= ...

  8. Java--异常与字符串

    1.处理异常 try-catch以及try-catch-finally try{ //一些会抛出的异常 }catch(Exception e){ //处理该异常的代码块 }catch(Exceptio ...

  9. C++中函数重载

    C++中函数重载使用顶层const修饰参数和不使用const修饰参数效果是一样的,如果定义了这样的重载函数会报函数重定义的错误. 追其原因,C++中的函数传递方式有三种,一种是值传递,就是拷贝,一种是 ...

  10. 基于v4l2 ffmpeg x264的视频远程监控(附上编译好的库文件)

    说明:主要是基于ghostyu网友整理的< arm mini2440 基于v4l2 ffmpeg x264的视频远程监控>.自己做了一遍,遇到不少问题,就整理记录下来. 1.平台 硬件:a ...