类似的问题还有: 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. 【点分治】【map】【哈希表】hdu4670 Cube number on a tree

    求树上点权积为立方数的路径数. 显然,分解质因数后,若所有的质因子出现的次数都%3==0,则该数是立方数. 于是在模意义下暴力统计即可. 当然,为了不MLE/TLE,我们不能存一个30长度的数组,而要 ...

  2. java web定时任务---Timer

    写在前面: 在最近的项目中需要每天定时对数据库表进行查询,并完成相关数据的更新操作.首先让我想到的是Timer类,记得在一开始维护那个老系统的时候,开了个接口,也涉及到了定时的操作.下面就记录下大概的 ...

  3. iOS 获取自定义cell上按钮所对应cell的indexPath.row的方法

    在UITableView或UICollectionView的自定义cell中创建一button,在点击该按钮时知道该按钮所在的cell在UITableView或UICollectionView中的行数 ...

  4. Debian6 安装Kscope(也适用于Ubuntu)

    参考:http://soft.chinabyte.com/os/134/12307634.shtml kscope1.6.2在这里下载,下载后解压出kscope-1.6.2.tar.gz. 在ubun ...

  5. sql获取汉字的拼音首字母的函数

    ql获取汉字的拼音首字母   if exists (select * from sysobjects where id = object_id(N'[fn_ChineseToSpell]') and ...

  6. webpack配置:图片处理、css分离和路径问题

    一.CSS中的图片处理: 1.首先在网上随便找一张图片,在src下新建images文件夹,将图片放在文件夹内 2.在index.html中写入代码:<div id="pic" ...

  7. JavaScript面向对象总结

    对象(Object)应该算是js中最为重要的部分,也是js中非常难懂晦涩的一部分.更是面试以及框架设计中各出没.本文章,主要参考JavaScript红宝书(JavaScript高级程序设计 第六章)以 ...

  8. javascript 的事件绑定和取消事件

    研究fabricjs中发现,它提供canvas.on('mousemove', hh) 来绑定事件, 提供 canvas.off()来取消绑定事件这样的接口,很是方便, 那我们就不妨探究一下内在的实现 ...

  9. win7安装centos7双系统

    采用硬盘安装 前景 打算用U盘安装,但是u盘是FAT32格式限制了文件4g大小,我官网下的iso镜像大于4g,只好采用硬盘安装. 其实U盘安装是最方便的,网上很多教程用UltraISO软件把U盘直接作 ...

  10. web应用程序指识别中的指纹收集

    web应用程序指纹识别是入侵前的关键步骤,假设通过指纹识别能确定web应用程序的名称及版本号.下一步就可以在网上搜索已公开的漏洞.或网上搜到其源码然后进行白盒的漏洞挖掘. 指纹识别的核心原理是通过正則 ...