C++ 模板详解(二):类模板的概念和基本使用方式

与函数模板相似地(C++模板详解(一):函数模板的概念和特性) ,类也能够被一种或多种类型参数化。例如,容器类就是一个具备这种特性的典型例子,它一般被用于管理某种特定类型的元素。只要使用类模板,咱们就能够实现容器类,而不须要肯定容器中元素的类型。html

1、类模板的实现

在这篇博文中,咱们使用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();
}

如上所示,类模板的声明和函数模板的声明很类似:在声明以前,咱们先声明参数类型的标识符spa

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

固然,也可使用关键字class来代替typename。在类模板的内部,类型T能够像其它的类型同样,用于声明成员变量和成员函数。在这个例子中,类的类型是Stack<T>,其中T是模板参数。所以,<font color="red"><strong>当在声明中须要使用该类的类型时,咱们必需要使用Stack<T></strong></font>。例如,若是要声明本身实现的拷贝构造函数和赋值运算符,那就应该这样来编写:code

template<typename T>
class Stack
{
	//...
    Stack(const Stack<T>& other);				// 这里的构造函数名称须要与类名相同(Stack)
    Stack<T>& operator=(const Stack<T>& other);	// 这里的拷贝构造函数须要使用类的类型(Stack<T>)
    //...
};

然而, 当须要使用类名而不是类的类型时,就应该只用Stack。例如,当指定类的名称,或是须要编写构造函数、析构函数时,就须要使用Stackhtm

(1.2) 类模板的实现

为了定义类模板的成员函数,咱们必需要指定该成员函数是一个函数模板(使用template<typename T>),并且还须要使用这个类模板的完整类型限定运算符Stack<T>::。所以,成员函数push的完整定义以下:blog

template<typename T>
void Stack<T>::push(const T& value)
{
	elems.push_back(value);
}

其它成员函数的实现也是相似的;和普通类定义相同,彻底也能够将成员函数的实现内联地写在类中,例如:get

template<typename T>
class Stack
{
    std::vector<T> elems;	// 存储元素的容器。
    
public:
    // ...
	bool empty() const {		// 检查栈是否为空。
		return elems.empty();
	}
};

2、类模板的使用

参见以下的main函数代码:string

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;
}

<font color="red"><strong>注意:</strong></font><strong>只有那些被调用了的成员函数,才会产生这些函数的实例化代码。</strong>io

因此,针对这个类模板,缺省的构造函数、pushtop方法都针对intstd::string进行了实例化。然而, pop方法只提供了std::string的实例化。这样作的好处是:模板

  • <strong>能够节省时间和空间。</strong>
  • <strong>对于那些未能提供全部成员函数中全部操做的类型,也可使用该类型来实例化类模板。</strong>

另外一方面,若是类中含有静态成员,那么用来实例化的每种类型,都会实例化这些静态成员。

原文出处:https://www.cnblogs.com/rosefinch/p/12294600.html

相关文章
相关标签/搜索