C++ 模板详解(二):类模板的概念和基本使用方式
2020-02-11 16:01:18来源:博客园 阅读 ()
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
的实例化。这样做的好处是:
- 可以节省时间和空间。
- 对于那些未能提供所有成员函数中所有操作的类型,也可以使用该类型来实例化类模板。
另一方面,如果类中含有静态成员,那么用来实例化的每种类型,都会实例化这些静态成员。
原文链接:https://www.cnblogs.com/rosefinch/p/12294600.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:C++对于C故有问题的改进
- C++ 转换函数搭配友元函数 2020-06-10
- C++ 自动转换和强制类型转换(用户自定义类类型) 2020-06-10
- C++ rand函数 2020-06-10
- C++ 友元函数 2020-06-10
- C++ 运算符重载 2020-06-10
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash