一、缺省模板参数

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

template <typename T, typename CONT = std::deque<T> >
class Stack
{

private:

CONT c_;
};

如果没有传第二个参数,默认为deque 双端队列,当然我们也可以传递std::vector<T>

下面程序借助标准模板容器管理内存来实现stack模板类:

Stack.h:

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

 
#ifndef _STACK_H_


#define _STACK_H_

#include <exception>


#include <deque>


using 
namespace std;

template <
typename T, 
typename CONT = deque<T> >


class Stack

{


public:

    Stack() : c_()

    {

    }

    ~Stack()

    {

    }

void Push(
const T &elem)

    {

        c_.push_back(elem);

    }

    
void Pop()

    {

        c_.pop_back();

    }

    T &Top()

    {

        
return c_.back();

    }

    
const T &Top() 
const

    {

        
return c_.back();

    }

    
bool Empty() 
const

    {

        
return c_.empty();

    }


private:

    CONT c_;

};

#endif 
// _STACK_H_

main.cpp:

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

 
#include 
"Stack.h"


#include <iostream>


#include <vector>


using 
namespace std;

int main(
void)

{

    
/*Stack<int> s;*/

    Stack<
int, vector<
int> > s;

    s.Push(
);

    s.Push(
);

    s.Push(
);

while (!s.Empty())

    {

        cout << s.Top() << endl;

        s.Pop();

    }

    
return 
;

}

输出为 3 2 1

即如果没有传递第二个参数,堆栈和压栈等操作直接调用deque<int> 的成员函数,也由deque<int> 管理内存。

如程序中传递vector<int> ,则由vector<int> 成员函数处理。

二、成员模板

来看下面的例子:

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

 
#include <iostream>


using 
namespace std;

template <
typename T>


class MyClass

{


private:

    T value;


public:

    
void Assign(
const MyClass<T> &x)

    {

        value = x.value;

    }

};

int main(
void)

{

    MyClass<
double> d;

    MyClass<
int> i;

d.Assign(d);        
// OK
    d.Assign(i);        
// Error
    
return 
;

}

因为i 和 d 的类型不同,故会编译出错。可以用成员模板的方法解决:

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

 
#include <iostream>


using 
namespace std;

template <
typename T>


class MyClass

{


private:

    T value;


public:

    MyClass() {}

    
template <
class X>

    MyClass(
const MyClass<X> &x) : value(x.GetValue())

    {

}

    
template <
class X>

    
void Assign(
const MyClass<X> &x)

    {

        value = x.GetValue();

    }

    T GetValue() 
const

    {

        
return value;

    }

};

int main(
void)

{

    MyClass<
double> d;

    MyClass<
int> i;

    d.Assign(d);        
// OK
    d.Assign(i);        
// OK

MyClass<
double> d2(i);

return 
;

}

为了支持  MyClass<double> d2(i); 故也要将拷贝构造函数实现为成员模板,同理,如果想支持 d = i ; 也要讲赋值运算符实现为成员

模板。
实际上auto_ptr<class> 中的实现就使用了成员模板,因为要支持类似下面的运算:

auto_ptr<X> x;

auto_ptr<Y> y;

x = y;


三、typename 关键字

看下面的例子:

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

 
#include <iostream>


using 
namespace std;

template <
typename T>


class MyClass

{


private:

    
typename T::SubType *ptr_;

};

class Test

{


public:

    
typedef 
int SubType;

};


int main(
void)

{

    MyClass<Test> mc;

    
return 
;

}

typename T::SubType *ptr_; 如果前面没有typename 修饰,则SubType会被认为是T类型内部的静态数据成员,推导下去,* 就不再认

为是指针,而被认为是乘号,编译的时候就出错了。加上修饰,就知道SubType 是T 内部的自定义类型,ptr是指向这种类型的指

针,编译通过。


四、派生类与模板、面向对象与泛型编程

(一)、派生类与模板

1、为了运行的效率,类模板是相互独立的,即独立设计,没有使用继承的思想。对类模板的扩展是采用适配器(adapter)来完成的。通用性是模板库的设计出发点之一,这是由泛型算法(algorithm)和函数对象(functor)等手段达到的。

2、派生的目标之一也是代码的复用和程序的通用性,最典型的就是MFC,派生类的优点是可以由简到繁,逐步深入,程序编制过程中可以充分利用前面的工作,一步步完成一个复杂的任务。

3、模板追求的是运行效率,而派生追求的是编程的效率。

(二)、面向对象与泛型编程

1、面向对象与泛型都依赖于某个形式的多态

面向对象

动态多态(虚函数)

泛型

静态多态(模板类,模板函数)

2、面向对象中的多态在运行时应用存在继承关系。我们编写使用这些类的代码,忽略基类与派生类之间的类型差异。只要使用基类指针或者引用,基类类型对象、派生类类型对象就可以共享相同的代码。

3、在泛型编程中,我们所编写的类和函数能够多态地用于编译时不相关的类型。一个类或一个函数可以用来操纵多种类型的对象。

参考:

C++ primer 第四版
Effective C++ 3rd
C++编程规范

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

  1. 从零开始学ios开发(三):第一个有交互的app

    感谢大家的关注,也给我一份动力,让我继续前进.有了自己的家庭有了孩子,过着上有老下有小的生活,能够挤出点时间学习真的很难,每天弄好孩子睡觉已经是晚上10点左右了,然后再弄自己的事情,一转眼很快就到12 ...

  2. 从零开始学C#——数据类型(三)

    C#数据类型 在C#中,变量分为以下几种类型: 值类型 引用类型 指针类型 值类型 值类型变量可以直接分配给一个值,他们是从类System.ValucTpyc中派生. 值类型直接包含数据,比如int. ...

  3. 从零开始学Linux系统(三)安装CentOS-7及软件包管理操作

    推荐博文: VirtualBox安装CentOS7步骤详解: https://my.oschina.net/AaronDMC/blog/840753 如何安装CentOS7字符界面 :http://b ...

  4. 从零开始学Electron笔记(三)

    在之前的文章我们介绍了一下Electron的菜单创建和事件绑定,其中提到了一个remote模块,接下来我们继续说一下Electron的这个remote模块. 官方关于remote模块的地址:https ...

  5. 从零开始学C++之构造函数与析构函数(二):初始化列表(const和引用成员)、拷贝构造函数

    一.构造函数初始化列表 推荐在构造函数初始化列表中进行初始化 构造函数的执行分为两个阶段 初始化段 普通计算段 (一).对象成员及其初始化  C++ Code  1 2 3 4 5 6 7 8 9 1 ...

  6. 从零开始设计SOA框架(三):请求参数的加密方式

    第二章中说明请求参数有哪些,主要是公共参数和业务参数,服务端需要对参数进行效验,已验证请求参数的合法性 参数效验前先解释下以下参数: 1.参数键值对:包括公共参数.业务参数      1.公共参数:按 ...

  7. 从零开始学 Web 之 ES6(三)ES6基础语法一

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  8. 从零开始学 Web 之 ES6(五)ES6基础语法三

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  9. 从零开始学 Web 之 Vue.js(三)Vue实例的生命周期

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

随机推荐

  1. 阿里云Linux服务器,配置JDK,MySQL

    云服务器配置:低配 Linux CentOS 7.4 64位 选择空白镜像: 安装图形界面 yum groups install "MATE Desktop" yum groups ...

  2. UML用例图之间的关系

    在画用例图的时候,理清用例之间的关系是重点.用例的关系有泛化(generalization).扩展(extend)和包含(include).其中include和extend最易混淆.下面我们结合实例彻 ...

  3. Android通知栏沉浸式/透明化完整解决方案

    转载请注明出处:http://www.cnblogs.com/cnwutianhao/p/6640649.html 参考文献:https://github.com/ljgsonx/adaptiveSt ...

  4. Android-Window(一)——初识Window

    Android-Window(一)--初识Window 学习自 <Android开发艺术探索> https://blog.csdn.net/qian520ao/article/detail ...

  5. CF1067D Computer Game

    link 题意: 有 n 道题,每个题可以做很多次但只能领悟一次,一开没有领悟任何题. 对于第 i 个题,正确率为 $p_i$ .领悟之前,做对这个题可以提升 $a_i$ 的能力值:领悟之后,做对这个 ...

  6. [USACO06JAN]Redundant Paths

    OJ题号:洛谷2860.POJ3177 题目大意: 给定一个无向图,试添加最少的边使得原图中没有桥. 思路: Tarjan缩点,然后统计度为$1$的连通分量的个数(找出原图中所有的桥). 考虑给它们每 ...

  7. Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) B. Verse Pattern 水题

    B. Verse Pattern 题目连接: http://codeforces.com/contest/722/problem/B Description You are given a text ...

  8. sql 计算两个经纬度点之间的距离

    这里用到的算法和地球半径等数据均来自网络,此文只作整理记录. 地球半径值采用赤道半径 6378137.0米,这是1980年的国际标准数据. //存储过程 CREATE FUNCTION [f_GetD ...

  9. 设置Azure WebSite黑白名单

    Azure WebSite服务默认是不提供黑白名单,也就是说任何Internet用户都可以访问Azure WebSite,那么我们如何来给我们的网站设置黑白名单? 这里有一种方式,可以通过配置网站的配 ...

  10. FCKeditor如何升级CKEditor及使用方法

    之前编辑器用的是FCKeditor,因为项目原因需要升级为最新版本4.2.2,发现是已经更名为CKEditor. 百度了一下,据官方的解释,CK是对FCK的代码的完全重写. 项目环境是asp.net的 ...