类似的问题还有: 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. 【函数式权值分块】【分块】bzoj1901 Zju2112 Dynamic Rankings

    论某O(n*sqrt(n))的带修改区间k大值算法. 首先对序列分块,分成sqrt(n)块. 然后对权值分块,共维护sqrt(n)个权值分块,对于权值分块T[i],存储了序列分块的前i块的权值情况. ...

  2. c pvr转存pvr.ccz格式 (转 http://www.cnblogs.com/howeho/p/3586379.html)

    pvr.ccz 是把pvr用zlib算法压缩后的图像格式,其优点是可以提升文件读取效率. 大多数情况下我们可以用一些工具来将pvr压缩到pvr.ccz ,下面提供一个c++方法来完成这个过程 int ...

  3. Java高级架构师(一)第03节:多模块多Web应用合并War包

    多模块.多Web应用合并war包 在日常的系统开发中,如果担心各个系统的资源同名覆盖,可以在总的War模块下放置一份最终的资源. 将版本号改成9.1.0.v20131115,ok 在Idea中的Mav ...

  4. Grunt上手指南(转)

    Grunt ,  javascript 我想先花点时间回忆一下作为一个前端需要做的工作(Loading...) JS合并 JS压缩 CSS压缩 CSS Sprite 图片优化 测试 静态资源缓存(版本 ...

  5. Oracle审计--AUD$占用空间较大处理方案

    Oracle 11G以后,数据库默认是开启审计功能的,因此有时候我们忘记了关闭该功能导致SYSTEM表空间暴满,但由于关闭审计功能需要重启数据库,此类操作生产环境下是不允许的,因此我们需要找出哪类审计 ...

  6. Swift,类的调用

    1.class或者struct如果没有实例没办法直接调用 (1)设置class后可直接调用 class S{ static var width:Int{ //static代表公有的,都可使用 retu ...

  7. Fatal error: Maximum execution time of 30 seconds exceeded in

    Fatal error: Maximum execution time of 30 seconds exceeded in C:\Program Files\Apache Software Found ...

  8. Heartbleed漏洞利用程序

    #!/usr/bin/python # Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford (jspenguin@jspe ...

  9. 【JavaScript】Bootstrap3-dialog挺好用

    参考资料: http://stackoverflow.com/questions/28436634/getting-error-uncaught-referenceerror-bootstrapdia ...

  10. Kubernetes用户指南(四)--应用检查和调试

    一.调试 当你的应用开始运行,那么DEBUG是不可避免的问题. 早些时候,我们在描述的是如何通过kubectl get pods来获得Pod的简单状态信息. 但是现在,这里有更多的方式来获得关于你的应 ...