我正在阅读Addison Wesley的“C ++模板:完整指南”一书,并对类模板的特化提出了疑问。我理解它是如何工作的,但是我很难理解你何时会使用给定示例中的这个功能。以下是Stack类的一般定义:
#include <vector>
#include <stdexcept>
template <typename T>
class Stack {
private:
std::vector<T> elems; // elements
public:
void push(T const&); // push element
void pop(); // pop element
T top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};
这是专业化
#include <deque>
#include <string>
#include <stdexcept>
#include "stack1.hpp"
template<>
class Stack<std::string> {
private:
std::deque<std::string> elems; // elements
public:
void push(std::string const&); // push element
void pop(); // pop element
std::string top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};
我的问题在于它似乎打破了关于封装的OOP原则。客户端是否需要知道有两个定义,可能在不同的头文件中,然后根据给予Stack类的类型T知道要包含哪个定义?在我看来,你最好在这个场景中实现两个不同的类,一个通用的Stack类和一个专门的StackString类。
思想?
答案 0 :(得分:1)
客户是否需要知道有两个定义,可能是 到不同的头文件,然后知道要包含哪一个 给予Stack类的类型T?
绝对不需要将它们放入两个不同的 open 标头中,即图书馆用户将看到并使用的标头。它们可能在内部组织在两个不同的实现头中,然后包含在用户将看到和包含的主要头中。但是用户既不知道 是显式特化,也不知道他使用。
// Stack.impl.hpp
// primary template:
template <typename T>
class Stack {
// [...]
};
// Stack_StringSpec.impl.hpp
#include "Stack.impl.hpp"
// explicit specialization:
template <>
class Stack<std::string> {
// [...]
};
// Stack.hpp
#include "Stack.impl.hpp" // Included for clarity
#include "Stack_StringSpec.impl.hpp"
请注意,在大多数情况下,仍然会记录专业化,因为它肯定存在,原因是用户应该/需要注意。 (以std::vector<bool>
为例。)
答案 1 :(得分:0)
一个专门的类只与非特定的变体共享基本名称,实际上你必须完全重写接口和实现,不能重用以前的代码。
最受欢迎的专业是std::vector<bool>
。 bool
类型需要1个字节,但实际上一个字节可以存储8个bool。当你需要一个bool数组时,在单个字节中包含更多的bool似乎是合理的,以减少内存消耗。这里的专业化可以实现这一点。
对于用户来说,一切都是透明的:你完全使用vector<bool>
作为vector<int>
,但是第二个依赖于动态的整数数组,第一个以完全不同的方式使用位。
专业化不一定必须在同一个标题中,但是当用户包含类时,应该注意使所有专业化都可见,否则他可能无法使用它们(你不想记得在使用vector<bool>
时包含其他文件。