返回完整目录

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. Java基础之函数

    函数(方法)的定义: 函数就是定义在类中的具有特定功能的一段独立的小程序. 为什么有函数:为了提高代码的复用性,对独立代码进行抽取,把抽取部分代码部分,定义成一个独立的功能,方便日后使用.Java中对 ...

  2. Mybatis(六)逆向工程generator

    逆向工程概述: MyBatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代 ...

  3. 毫无基础的人入门Python,Python新手入门教程2

    1.6 面向对象和内存分析086.面向对象和面向过程的区别_执行者思维_设计者思维087.对象的进化故事088.类的定义_类和对象的关系089.构造函数__init__090.实例属性_内存分析091 ...

  4. ES数据库重建索引——Reindex(数据迁移)

    应用背景: 1.当你的数据量过大,而你的索引最初创建的分片数量不足,导致数据入库较慢的情况,此时需要扩大分片的数量,此时可以尝试使用Reindex. 2.当数据的mapping需要修改,但是大量的数据 ...

  5. ES数据库搜索

    1.倒排索引 1.倒排索引和正向索引 在全文搜索里,文档数据离不开搜索,而搜索离不开索引(没有索引搜索会很低效),倒排索引(Inverted index)是全文搜索系统里最高效的索引方法和数据结构,E ...

  6. 蒲公英 · JELLY技术周刊 Vol.16 谷歌首个线上 Web 开发者大会

    蒲公英 · JELLY技术周刊 Vol.16 近期,谷歌有史以来的第一次线上谷歌 Web 开发者大会,Web Vitals.PWA.DevTools 和 Lighthouse 6.0 等一系列特性或产 ...

  7. Python os.fstatvfs() 方法

    概述 os.fstatvfs() 方法用于返回包含文件描述符fd的文件的文件系统的信息,类似 statvfs().高佣联盟 www.cgewang.com Unix上可用. fstatvfs 方法返回 ...

  8. PHP array_push() 函数

    实例 向数组尾部插入 "blue" 和 "yellow": <?php$a=array("red","green" ...

  9. PHP restore_exception_handler() 函数

    定义和用法 restore_exception_handler() 函数恢复之前的异常处理程序. 该函数用于在通过 set_exception_handler() 函数改变后恢复之前的异常处理程序. ...

  10. PHP is_int() 、is_integer()、is_long() 函数

    is_int() 函数用于检测变量是否是整数.高佣联盟 www.cgewang.com 注意: 若想测试一个变量是否是数字或数字字符串(如表单输入,它们通常为字符串),必须使用 is_numeric( ...