返回完整目录

2.1 类模板Stack的实现 Implementation of Class Template Stack

正如函数模板,可以如下方式在一个头文件中声明和定义类Stack<>

// basics/stack1.hpp

#include <vector>
#include <cassert> template <typename T>
class Stack
{
private:
std::vector<T> elems; //元素 public:
void push(T const& elem); //压入元素
void pop(); // 弹出元素
T const& top() const; //返回顶上的元素
bool empty() //返回栈stack是否为空
{
return elems.empty();
}
}; template <typename T>
void Stack<T>::push(T const& elem)
{
elems.push_back(elem); //将elem的拷贝放入elems末尾
} template <typename T>
void Stack<T>::pop()
{
assert(!elems.empty());
elems.pop_back(); //移除最后一个元素
} template <typename T>
T const& Stack<T>::top() const
{
assert(!elems.empty());
return elems.back(); //返回最后一个元素
}

正如所看到的,该类模板使用C++标准库的vector<>实现,这样便无需实现内存管理、拷贝控制和赋值运算,这样便可以将重心放在类模板的接口上。

2.1.1 声明类模板 Declaration of Class Templates

声明类模板与声明函数模板类似:在声明之前,必须声明一个或多个类型参数的标识符。再一次,T是一个常用的标识符:

template <typename T>
class Stack
{
...
};

此处的关键字typename也可以用class代替:

template <class T>
class Stack
{
...
};

在类模板中,T可以像其他任何类型一样用于声明成员和成员函数(member function)。该例子中,T用于声明成员的类型为T的向量vector,用于声明成员函数push()使用T类型作为参数,用于声明成员函数top()的返回类型。

template <typename T>
class Stack
{
private:
std::vector<T> elems; //元素 public:
void push(T const& elem); //压入元素
void pop(); // 弹出元素
T const& top() const; //返回顶上的元素
bool empty() //返回栈stack是否为空
{
return elems.empty();
}
};

该类的类型为Stack,其中T为模板参数。因此,只要在声明中使用该类的类型,必须使用Stack,除非模板参数可以推断而得。然而,在类模板内,使用没有模板实参的类名意味着将类模板实参作为模板参数(However, inside a class template using the class name not followed by template arguments represents the class with its template parameters as its arguments.)(详见13.2.3节)。

比如,如果必须声明构造函数和赋值运算符,这通常看起来像这样:

template <typename T>
class Stack
{
...
Stack(Stack const&); //拷贝构造
Stack& operator=(Stack const&); //赋值运算符
};

这与如下形式等价:

template <typename T>
class Stack
{
...
Stack(Stack<T> const&); //拷贝赋值
Stack<T>& operator=(Stack<T> const&); //赋值运算符
};

但通常意味着对特殊模板参数的特殊处理,因此第一种形式更好。

然而,在类结构之外需要指定模板参数:

template <typename T>
bool operator==(Stack<T> const& lhs, Stack<T> const& rhs);

注意到在需要类名而不是类的类型的地方,仅仅使用Stack便可以。这特别是在构造函数和析构函数名字的情形中。

与非模板类不同,不能在函数内部或者块作用域(block scope)内声明类模板。通常,模板只能定义在全局作用域(global scope)或者命名空间作用域(namespace scope)或者类声明内(详见12.1节)。

2.1.2 成员函数实现 Implementation of Member Functions

定义类模板的成员函数必须指定这是一个模板且必须使用类模板的完整类型限制。因此,类型Stack的成员函数push()的实现为

template <typename T>
void Stack<T>::push(T const& elem)
{
elems.push_back(elem); //将elem的拷贝放入elems末尾
}

该情况下,成员向量的push_bask()方法被调用,将元素放入向量vector的末尾。

注意到向量vector的pop_back()将移除最后一个元素但不返回,这行为的原因是异常安全(exception safety)。不可能实现一个返回移除元素的完全异常安全的pop()版本(该问题首先由Tom Cargill在[CargilExceptionSafety]中的第10项条款[SutterExceptional]中讨论)。然而,如果忽略该危险,可以实现返回移除的元素的pop()。为实现此功能,简单地使用T来声明类型为元素类型的局部变量:

template <typename T>
T Stack<T>::pop()
{
assert(!elems.empty());
T elem = elems.back(); //保存最后一个元素
elems.pop_back(); //移除最后一个元素
return elem; //返回保存元素的拷贝
}

由于当vector中没有元素时,back()(返回最后一个元素)和pop_back()(移除最后一个元素)都将有未定义的行为,因此需要检查栈是否为空。如果为空,则断言(assert),因为在空的栈上调用pop()是错误的。在top()上也需要这么做,它返回顶上的元素但不移除:

template <typename T>
T const& Stack<T>::top() const
{
assert(elems.empty());
return elems.back(); //返回最后一个元素
}

当然,对于任何成员函数,也可以将类模板的成员函数在类的声明中实现为inline,比如:

template <typename T>
class Stack
{
...
void push(T const& elem)
{
elems.push_back(elem); //将elem放入末尾
}
};

C++ Templates (2.1 类模板Stack的实现 Implementation of Class Template Stack)的更多相关文章

  1. c++11-17 模板核心知识(二)—— 类模板

    类模板声明.实现与使用 Class Instantiation 使用类模板的部分成员函数 Concept 友元 方式一 方式二 类模板的全特化 类模板的偏特化 多模板参数的偏特化 默认模板参数 Typ ...

  2. C++解析(26):函数模板与类模板

    0.目录 1.函数模板 1.1 函数模板与泛型编程 1.2 多参数函数模板 1.3 函数重载遇上函数模板 2.类模板 2.1 类模板 2.2 多参数类模板与特化 2.3 特化的深度分析 3.小结 1. ...

  3. 初步C++类模板学习笔记

    类模板 实现:在上课时间的定义给它的一个或多个参数,这些参数代表了不同的数据类型.                              -->抽象的类. 在调用类模板时, 指定參数, 由编 ...

  4. C++程序设计方法4:类模板

    类模板 在定义类时也可以将一些类型抽象出来,用模板参数来替换,从而使类更具有通用性.这种类被称为模板类,例如: template <typename T> class A { T data ...

  5. C++ 模板学习 函数模板、类模板、迭代器模板

    使用模板能够极大到使得代码可重用. 记录一下,方便后续使用. 1. 函数模板,支持多种类型参数 #include <stdio.h> #include <math.h> //函 ...

  6. C++ 函数模板与类模板(使用 Qt 开发编译环境)

    注意:本文中代码均使用 Qt 开发编译环境,如有疑问和建议欢迎随时留言. 模板是 C++ 支持参数化程序设计的工具,通过它可以实现参数多态性.所谓参数多态性,就是将程序所处理的对象的类型参数化,使得一 ...

  7. C++入门经典-例9.3-类模板,简单类模板

    1:使用template关键字不但可以定义函数模板,而且可以定义类模板.类模板代表一族类,它是用来描述通用数据类型或处理方法的机制,它使类中的一些数据成员和成员函数的参数或返回值可以取任意数据类型.类 ...

  8. C++ Templates (2.2 使用Stack类模板 Use of Class Template Stack )

    返回完整目录 目录 2.2 使用Stack类模板 Use of Class Template Stack 2.2 使用Stack类模板 Use of Class Template Stack 在C++ ...

  9. C++ Templates (2.3 类模板的局部使用 Partial Usage of Class Templates)

    返回完整目录 目录 2.3 类模板的局部使用 Partial Usage of Class Templates 2.3.1 Concepts 2.3 类模板的局部使用 Partial Usage of ...

随机推荐

  1. https://blog.csdn.net/yongchaocsdn/article/details/53355296

    https://blog.csdn.net/yongchaocsdn/article/details/53355296

  2. Spring+hibernate+JSP实现Piano的数据库操作---5.JSP页面

    1.index.jsp <%-- Created by IntelliJ IDEA. User: lenovo Date: 2020/3/25 Time: 14:09 To change thi ...

  3. this指向面试题两则

    面试题1 let len = 10; function fn() { console.info(this.len) } fn(); // A let Person = { len: 5, say: f ...

  4. Django学习路5_更新和删除数据库表中元素

    查找所有的元素 Student.objects.all() 查找单个元素 Student.objects.get(主键=值) 主键 pk = xxx 更新数据库数据后进行保存 stu.save() 删 ...

  5. Python os.chmod() 方法

    概述 os.chmod() 方法用于更改文件或目录的权限.高佣联盟 www.cgewang.com 语法 chmod()方法语法格式如下: os.chmod(path, mode) 参数 path - ...

  6. PHP filectime() 函数

    定义和用法 filectime() 函数返回指定文件的上次修改时间. 该函数将检查文件的日常修改情况和 inode 修改情况.inode 修改情况是指:权限的修改.所有者的修改.用户组的修改或其他元数 ...

  7. PHP is_dir() 函数

    定义和用法 is_dir() 函数检查指定的文件是否是一个目录. 如果目录存在,该函数返回 TRUE. 语法 is_dir(file) 参数 描述 file 必需.规定要检查的文件. 提示和注释 注释 ...

  8. PHP parse_ini_file() 函数

    定义和用法 parse_ini_file() 函数解析一个配置文件(ini 文件),并以数组的形式返回其中的设置. 语法 parse_ini_file(file,process_sections) 参 ...

  9. PDO::inTransaction

    PDO::inTransaction — 检查是否在一个事务内(PHP 5 >= 5.3.3, Bundled pdo_pgsql) 说明 语法 bool PDO::inTransaction ...

  10. PHP bin2hex() 函数

    实例 把 "Hello World!" 转换为十六进制值: <?php 高佣联盟 www.cgewang.com$str = bin2hex("Hello Worl ...