C++ 类模板详解(一):概念和基本使用方式
与函数模板类似地(C++模板详解(一):函数模板的概念和特性) ,类也可以被一种或多种类型参数化。例如,容器类就是一个具有这种特性的典型例子,它通常被用于管理某种特定类型的元素。只要使用类模板,我们就可以实现容器类,而不需要确定容器中元素的类型。
一、类模板的实现
在这篇博文中,我们使用Stack
作为类模板的例子。
(1.1) 类模板的声明
#include <vector>
#include <deque>
#include <stdexcept>
template<typename T>
class Stack
{
std::vector<T> elems; // 存储元素的容器。
public:
void push(const T& value); // 将元素压入栈中。
void pop(); // 将栈顶元素弹出栈。
T top() const; // 查看栈顶元素的副本。
bool empty() const { // 检查栈是否为空。
return elems.empty();
}
};
template<typename T>
void Stack<T>::push(const T& value)
{
elems.push_back(value);
}
template<typename T>
void Stack<T>::pop()
{
if (elems.empty()) {
throw std::out_of_range("Stack<>::pop(): empty stack");
}
elems.pop_back();
}
template<typename T>
T Stack<T>::top() const
{
if (elems.empty()) {
throw std::out_of_range("Stack<>::pop(): empty stack");
}
return elems.back();
}
如上所示,类模板的声明和函数模板的声明很相似:在声明之前,我们先声明参数类型的标识符
template<typename /*class*/ T>
class Stack
{
//...
};
当然,也可以使用关键字class
来代替typename
。在类模板的内部,类型T
可以像其它的类型一样,用于声明成员变量和成员函数。在这个例子中,类的类型是Stack<T>
,其中T
是模板参数。因此,当在声明中需要使用该类的类型时,我们必须要使用Stack<T>
。例如,如果要声明自己实现的拷贝构造函数和赋值运算符,那就应该这样来编写:
template<typename T>
class Stack
{
//...
Stack(const Stack<T>& other); // 这里的构造函数名称需要与类名相同(Stack)
Stack<T>& operator=(const Stack<T>& other); // 这里的拷贝构造函数需要使用类的类型(Stack<T>)
//...
};
然而, 当需要使用类名而不是类的类型时,就应该只用Stack
。例如,当指定类的名称,或是需要编写构造函数、析构函数时,就需要使用Stack
。
(1.2) 类模板的实现
为了定义类模板的成员函数,我们必须要指定该成员函数是一个函数模板(使用template<typename T>
),而且还需要使用这个类模板的完整类型限定运算符Stack<T>::
。因此,成员函数push
的完整定义如下:
template<typename T>
void Stack<T>::push(const T& value)
{
elems.push_back(value);
}
其它成员函数的实现也是类似的;和普通类定义相同,完全也可以将成员函数的实现内联地写在类中,例如:
template<typename T>
class Stack
{
std::vector<T> elems; // 存储元素的容器。
public:
// ...
bool empty() const { // 检查栈是否为空。
return elems.empty();
}
};
二、类模板的使用
参见如下的main
函数代码:
int main()
{
try
{
Stack<int> intStack;
Stack<std::string> stringStack;
// 使用int栈
intStack.push(7);
std::cout << intStack.top() << std::endl;
// 使用string栈
stringStack.push("hello");
std::cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
}
catch (std::exception &ex)
{
std::cerr << "Exception: " << ex.what() << std::endl;
return EXIT_FAILURE;
}
return 0;
}
注意:只有那些被调用了的成员函数,才会产生这些函数的实例化代码。
所以,针对这个类模板,缺省的构造函数、push
、top
方法都针对int
、std::string
进行了实例化。然而, pop
方法只提供了std::string
的实例化。这样做的好处是:
- 可以节省时间和空间。
- 对于那些未能提供所有成员函数中所有操作的类型,也可以使用该类型来实例化类模板。
另一方面,如果类中含有静态成员,那么用来实例化的每种类型,都会实例化这些静态成员。
C++ 类模板详解(一):概念和基本使用方式的更多相关文章
- C++ 函数模板&类模板详解
在 C++ 中,模板分为函数模板和类模板两种.函数模板是用于生成函数的,类模板则是用于生成类的. 函数模板&模板函数 类模板&模板类 必须区分概念 函数模板是模板,模板函数时 ...
- 28.C++- 单例类模板(详解)
单例类 描述 指在整个系统生命期中,一个类最多只能有一个实例(instance)存在,使得该实例的唯一性(实例是指一个对象指针) , 比如:统计在线人数 在单例类里,又分为了懒汉式和饿汉式,它们的区 ...
- 25.C++- 泛型编程之函数模板(详解)
本章学习: 1)初探函数模板 2)深入理解函数模板 3)多参函数模板 4)重载函数和函数模板 当我们想写个Swap()交换函数时,通常这样写: void Swap(int& a, int&am ...
- C++模板详解(三):参数化声明详解
在前两节中(C++模板详解(一).C++模板详解(二)),我们了解了函数模板和类模板的基本概念和使用方法.在这篇博文里,我们主要来详细地阐述一下"模板的参数声明"这个话题,并且也谈 ...
- C++模板详解
参考:C++ 模板详解(一) 模板:对类型进行参数化的工具:通常有两种形式: 函数模板:仅参数类型不同: 类模板: 仅数据成员和成员函数类型不同. 目的:让程序员编写与类型无关的代码. 注意:模板 ...
- 26.C++- 泛型编程之类模板(详解)
在上章25.C++- 泛型编程之函数模板(详解) 学习了后,本章继续来学习类模板 类模板介绍 和函数模板一样,将泛型思想应用于类. 编译器对类模板处理方式和函数模板相同,都是进行2次编译 类模板通 ...
- UML类图详解_关联关系_多对一
首先先来明确一个概念,即多重性.什么是多重性呢?多重性是指两个对象之间的链接数目,表示法是“下限...上限”,最小数据为零(0),最大数目为没有设限(*),如果仅标示一个数目级上下限相同. 实际在UM ...
- c3p0-config.xml模板详解
c3p0-config.xml模板详解 <c3p0-config> <default-config> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数.De ...
- Android中Application类的详解:
Android中Application类的详解: 我们在平时的开发中,有时候可能会须要一些全局数据.来让应用中的全部Activity和View都能訪问到.大家在遇到这样的情况时,可能首先会想到自定义一 ...
随机推荐
- SpringBoot系列——启用https
前言 有时候我们需要使用https安全协议,本文记录在SpringBoot项目启用https 生成证书 自签名证书 使用java jdk自带的生成SSL证书的工具keytool生成自己的证书 1.打开 ...
- 【题解】JXOI2018游戏(组合数)
[题解]JXOI2018游戏(组合数) 题目大意 对于\([l,r]\)中的数,你有一种操作,就是删除一个数及其所有倍数.问你删除所有数的所有方案的步数之和. 由于这里是简化题意,有一个东西没有提到: ...
- $POJ2411\ Mondriaan's\ Dream$ 状压+轮廓线$dp$
传送门 Sol 首先状压大概是很容易想到的 一般的做法大概就是枚举每种状态然后判断转移 但是这里其实可以轮廓线dp 也就是从上到下,从左到右地放方块 假设我们现在已经放到了$(i,j)$这个位置 那么 ...
- 智能反射表面(可重构智能表面)Large Intelligent surface 最新综述整理
闻道洛阳花正好,家家遮户春风.道人饮处百壶空.年年花下醉,看尽几番红. 此拐又从何处去,飘蓬一任西东.语声虽异笑声同.一轮清夜月,何处不相逢. ---- 临江仙·与刘拐 更多精彩内容请关注微信公众号 ...
- AES Base64 C++加密工具
最近写了一段C++ 的AES 加密的工具,在github 上找了很多工具,都不太好用,Star数字比较的高的一个,只能加密16个字节的,加密数字长数据,会出现乱码,不能使用 这里附上代码,文件以供大家 ...
- Go网络文件传输
流程分析 借助TCP完成文件的传输,基本思路如下: 发送方(客户端)向服务端发送文件名,服务端保存该文件名. 接收方(服务端)向客户端返回一个消息ok,确认文件名保存成功. 发送方(客户端)收到消息后 ...
- HashMap 源码赏析 JDK8
一.简介 HashMap源码看过无数遍了,但是总是忘,好记性不如烂笔头. 本文HashMap源码基于JDK8. 文章将全面介绍HashMap的源码及HashMap存在的诸多问题. 开局一张图,先来看看 ...
- [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause报错问题的解决
run SQL: select version(),@@sql_mode;SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY','' ...
- head查询
• must子句:文档必须匹配must查询条件:• should子句:文档应该匹配should子句查询的一个或多个:• must_not子句:文档不能匹配该查询条件:• filter子句:过滤器,文档 ...
- jav设计模之的动态代理
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...