类似的问题还有: why can't class template use Handle Class Pattern to hide its implementation? || why there are linker problems (undefined reference) to my class template?

我出现问题的源码(见main.cpp,Stack.h,Stack.cpp)(本来是准备用来展示Handle Class Pattern如何实现implementation-hiding),报错如下:

问题的本质&解决办法:

http://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor

http://www.parashift.com/c++-faq-lite/templates-defn-vs-decl.html

http://stackoverflow.com/questions/5417465/separating-template-interface-and-implementation-in-c

http://stackoverflow.com/questions/18121071/hiding-template-implementation-details-from-doxygen

方法1:Explicitly instantiate the template, and its member definitions

方法2:Copy the implemtation code of the class template into its header file

总结:

虽然有2种解决办法,但是方法一显然“太笨”,而且“太不灵活”

So, if you plan to create your own class template, then you just don't need to consider enforcing implementation hiding as you do to normal classes, the only way to hide the implementation of  a class template is not to provide its header.

On the other hand, if you decide to design something to be a class template, you must be sure there's nothing need to be hidden for that template, for example: encryption algorithm or other sensitive stuff.

Insight Comment:

The very goal of template is to create a "pattern" so that the compiler can generate classes and functions for a multitude of unrelated types. If you hide this pattern, how do you expect the compiler to be able to generate those classes and functions ?

代码:

main.cpp

 #include "Stack.h"

 #include <iostream>

 using namespace std;

 class Box {
public:
Box():data(), ID(num++) { cout << "Box" << ID << " cons" << endl; }
Box(const Box &copy): data(copy.data), ID(num++) { cout << "Box" << ID << " copy cons" << endl; }
~Box() { cout << "Box" << ID << " des" << endl; }
int data;
private:
static int num;
const int ID;
}; int Box::num = ; int main()
{
Box b1,b2,b3;
Stack<Box> bstack;
bstack.push(b1);
bstack.push(b2);
bstack.push(b3);
return ;
}

Stack.h

 #ifndef STACK_H
#define STACK_H #include <cstddef> template <typename T>
class StackImpl; // Stack implementation (hidden), private part
// will not be seen by clients template <typename T>
class Stack
{
public:
Stack();
~Stack();
/**
Inserts a new element at the top of the stack,
above its current top element.
The content of this new element is
initialized to a copy of val.
@param val value to which the inserted element is initialized
*/
void push(const T &val);
/**
@return a reference to the top element in the stack
*/
T& top();
/**
@return a const reference to the top element in the stack
*/
const T& top() const;
/**
Removes the element on top of the stack.
This calls the removed element's destructor.
*/
void pop();
/**
@return the number of elements in the stack.
*/
size_t size();
private: StackImpl<T> *impl; // Stack implementation (hidden), private part
// will not be seen by clients }; #endif // STACK_H

Stack.cpp

 #include "Stack.h"

 #include <stdexcept>

 using namespace std;

 template <typename T>
class Link {
public: T data;
Link *next; Link(const T &_data): data(_data), next(NULL) {}
Link(const T &_data, Link *_next): data(_data), next(_next) {}
~Link() {
next = NULL;
} }; template <typename T>
class StackImpl {
public: // even though they're public, but they're not in the header, thus it's safe Link<T> *head; size_t size; StackImpl(): head(NULL) {}
~StackImpl() {
Link<T> *ptr = head;
while (ptr != NULL) {
ptr = head->next;
delete head;
head = ptr;
}
size = ;
}
}; template <typename T>
Stack<T>::Stack(): impl(new StackImpl<T>()) {} template <typename T>
Stack<T>::~Stack() {
if (impl != NULL)
delete impl;
}
/**
Inserts a new element at the top of the stack,
above its current top element.
The content of this new element is
initialized to a copy of val.
@param val value to which the inserted element is initialized
*/
template <typename T>
void Stack<T>::push(const T &val)
{
impl->head = new Link<T>(val, impl->head);
++(impl->size);
}
/**
@return a reference to the top element in the stack
*/
template <typename T>
T& Stack<T>::top()
{
if (impl->head == NULL)
throw runtime_error("empty stack");
return impl->head->data; }
/**
@return a const reference to the top element in the stack
*/
template <typename T>
const T& Stack<T>::top() const
{
if (impl->head == NULL)
throw runtime_error("empty stack");
return impl->head->data;
}
/**
Removes the element on top of the stack.
This calls the removed element's destructor.
*/
template <typename T>
void Stack<T>::pop()
{
if (impl->head == NULL)
throw runtime_error("empty stack");
Link<T> *ptr = impl->head->next;
delete impl->head;
impl->head = ptr;
--(impl->size);
} /**
@return the number of elements in the stack.
*/
template <typename T>
size_t Stack<T>::size() {
return impl->size;
}

c++ why can't class template hide its implementation in cpp file?的更多相关文章

  1. C++中template的.h文件和.cpp文件的问题

    在C++中,用到类模板时,如果类似一般的类声明定义一样,把类声明放在.h文件中,而具体的函数定义放在.cpp文件中的话,会发现编译器会报错.如类似下面代码: //test.h文件 #ifndef TE ...

  2. c++模板类的使用,编译的问题

    1,模板类编译的问题 前两天在写代码时,把模板类的声明和分开放在两个文件中了,类似于下面这样: stack.hpp: #ifndef _STACK_HPP #define _STACK_HPP tem ...

  3. 增强采样软件PLUMED的安装与使用

    技术背景 增强采样(Enhanced Sampling)是一种在分子动力学模拟中常用的技术,其作用是帮助我们更加快速的在时间轴上找到尽可能多的体系结构及其对应的能量.比如一个氢气的燃烧反应,在中间过程 ...

  4. c++ simple class template example: Stack

    main.cpp #include "Stack.h" #include <iostream> using namespace std; class Box { pub ...

  5. 模板函数(template function)出现编译链接错误(link error)之解析

    总的结论:    将template function 或者 template class的完整定义直接放在.h文件中,然后加到要使用这些template function的.cpp文件中. 1. 现 ...

  6. 用T4 Template生成代码

    1 T4语法 T4的语法与ASP.NET的方式比较类似.主要包括指令.文本块.控制块. 1.1    指令 指令主要包括template, output, assembly, import, incl ...

  7. A Simple C++ Template Class that Matches a String to a Wildcard Pattern

    A recently implemented enhanced wildcard string matcher, features of which including, Supporting wil ...

  8. How to organize the Template Files in C++

    Normally you put class definitions in a header file and method definitions in a source file. Code th ...

  9. idea: Unable to parse template "class"

    使用idea创建文件时,报“Cannot Create Class”.具体错误为: Unable to parse template "Class" error meesage: ...

随机推荐

  1. 【带修莫队】【权值分块】bzoj3196 Tyvj 1730 二逼平衡树

    这题用了三种算法写: 分块+二分:O(n*sqrt(n*log(n)) 函数式权值分块:O(n*sqrt(n)) 带修莫队+权值分块:O(n5/3) 结果……复杂度越高的实际上跑得越快……最后这个竟然 ...

  2. 【知识点总结】NOIP前夕 2014.11.4

    2014.11.4 7:33 还有三天半就要NOIP,圈一下要背的知识点: 一.数论 1.素数判断 2.筛法求素数 3.求一个数的欧拉函数值 4.预处理欧拉函数 5.卡塔兰数递推式 6.快速幂(模素数 ...

  3. 【匈牙利算法】BZOJ1059-[ZJOI2007]矩阵游戏

    [题目大意] 给出一个局部染色的矩阵,问能否通过交换行或者列使得最后又一条对角线全部被染色过? [思路] 无论如何交换,同一行的格子依然在同一行,同一列的格子依然在同一列.所以只需找出n个行号列号均不 ...

  4. 【KMP】BZOJ3670-[Noi2014]动物园

    [题目大意][依然借用别人的概括]给定一个长为L的字符串(L<=100W),求一个num数组,num[i]表示长度为i的前缀中字符串S’的数量,其中S‘既是该前缀的前缀也是该前缀的后缀,且|S' ...

  5. sql字段字符用做其他类型查询

    select * FROM aa where parent = %@ ORDER BY cast(seq as integer) ASC

  6. winform TreeView树节点上下移动

    /// <summary> /// 上移 /// </summary> /// <param name="sender"></param& ...

  7. ArcGIS中的多个栅格波段合成一幅影像

    此处用到了ArcGIS栅格处理中的Composite Bands工具( Data Management Tools --> Raster --> Raster Processing).具体 ...

  8. 基于jquery类库的绘制二维码的插件jquery.qrcode.js

     jquery.qrcode.min.js 如下 (function(r){r.fn.qrcode=function(h){var s;function u(a){this.mode=s;this.d ...

  9. 用Thunderbird以HTML发邮件,收件人却总是收到文本邮件

    要在通讯录里面,把你要发送的人设置可以接收HTML格式的邮件,那么你才能发出HTML格式. 否则,Thunderbird默认你所发的收件人无法接收HTML格式邮件.

  10. 在Linux中切换用户时变成-bash-4.3$

    增加普通用户 [root@git-node1 ~]#useradd nulige [root@git-node1 ~]#passwd nulige 输入两次密码 [root@git-node1 ~]# ...