一、缺省模板参数

回顾前面的文章,都是自己管理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. 微信小程序入门实例之记事本

    主要实现思想都在代码的注释中,项目源码见github 首先上项目目录 app.js文件代码如下: //app.js App({ onLaunch: function() { //调用API从本地缓存中 ...

  2. AngularJS之jeDate日期控件基本使用

    业务背景: 初学AngularJs,最近一段时间,因业务需求,要求日期选择带有快捷键.时分秒等.鉴于AngularJS组件库ui-bootstrap没有此功能,找了一款基于原生JS实现的插件-jeDa ...

  3. php版本CKEditor 4和CKFinder安装及配置

    下载并解压CKEditor 4和CKFinder CKEditor 4下载地址:https://ckeditor.com/cke4/builder,选择自定义的版本,记得加上中文语言包 CKFinde ...

  4. 安装 intelliJ idea 。 快速学会kotlin

    用户界面主题 - 默认插件-功能插件 调整 idea 到你的任务 idea 有 许多 工具 可用 通过 默认. 你能够设置 你需要的. 跳过 剩下的 设置默认 . 回到 用户界面主题. 下一步:功能插 ...

  5. 牛客网某比赛 I 小乐乐学博弈 博弈论

    题目大意: 有两堆石子\(n\)和\(m\),每次可以拿\(1 \sim k\)个 \(k >= |n - m|\) 问先手必胜? 把限制条件去掉才有意思 首先考虑两堆相等,那么先手怎么操作,后 ...

  6. VM 操作系统实例化(基于 KVM 的虚拟化研究及应用--崔泽永(2011))的论文笔记

    一.VM操作系统实例化 1.建立虚拟磁盘镜像 虚拟磁盘镜像在逻辑上是提供给虚拟机使用的硬盘, 在物理上可以是 L inux系 统内一普通镜像文件, 也可以是真实的物理磁盘或分区. 本方案设计中将虚拟机 ...

  7. 模板 树上求LCA 倍增和树链剖分

    //233 模板 LCA void dfs(int x,int f){ for(int i=0;i<E[x].size();i++){ int v = E[x][i]; if(v==f)cont ...

  8. Centos 安装Percona Toolkit工具集

    1.下载 下载地址:   https://www.percona.com/downloads/percona-toolkit/LATEST/ [root@bogon ~]# wget https:// ...

  9. FireDAC 下的 Sqlite [2] - 第一个例子

    为了方便测试, 我把官方提供的 C:\Users\Public\Documents\Embarcadero\Studio\14.0\Samples\data\FDDemo.sdb 复制了一份到 C:\ ...

  10. x270

    https://thinkpad.lenovo.com.cn/product/93964.html