我正在阅读Addison的“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知道应该包含哪一个定义?在我看来,您最好在这个场景中实现两个不同的类,一个是通用堆栈类,另一个是专门的StackString类。
有什么想法?
发布于 2014-10-07 19:29:08
客户端是否需要知道有两个定义,可能存在于不同的头文件中,然后根据Stack类的类型T知道应该包含哪一个定义?
绝对没有必要将它们放入两个不同的打开头中,即库的用户将看到和使用的标题。它们可能在内部组织在两个不同的实现头中,然后包含在用户将看到和包含的主实现头中。但是用户既不知道有一个明确的专门化,也不知道他正在使用一个专门化。
// 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>为例。)
发布于 2014-10-07 20:17:21
专门化类只与非专用变量共享基本名称,实际上您必须完全重写接口和实现,不能重用以前的代码。
最流行的专业是std::vector<bool>。bool类型需要一个字节,但实际上一个字节可以存储8个bools。当您需要一个bools数组时,为了减少内存消耗,将更多的bools打包在一个字节中似乎是合理的。这里的专门化允许精确地实现这一点。
对于用户来说,一切都是透明的:您使用的vector<bool>与vector<int>完全一样,但是第二个依赖于一个动态的in数组,而第一个则以完全不同的方式处理比特。
专门化不必在同一个标题中,但是当用户包含类时,您应该注意使所有的专门化可见,否则他可能无法使用它们(当您使用vector<bool>时,您不想记住包含另一个文件)。
https://stackoverflow.com/questions/26243586
复制相似问题