c++ why can't class template hide its implementation in cpp file?
类似的问题还有: 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 ©): 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?的更多相关文章
- C++中template的.h文件和.cpp文件的问题
在C++中,用到类模板时,如果类似一般的类声明定义一样,把类声明放在.h文件中,而具体的函数定义放在.cpp文件中的话,会发现编译器会报错.如类似下面代码: //test.h文件 #ifndef TE ...
- c++模板类的使用,编译的问题
1,模板类编译的问题 前两天在写代码时,把模板类的声明和分开放在两个文件中了,类似于下面这样: stack.hpp: #ifndef _STACK_HPP #define _STACK_HPP tem ...
- 增强采样软件PLUMED的安装与使用
技术背景 增强采样(Enhanced Sampling)是一种在分子动力学模拟中常用的技术,其作用是帮助我们更加快速的在时间轴上找到尽可能多的体系结构及其对应的能量.比如一个氢气的燃烧反应,在中间过程 ...
- c++ simple class template example: Stack
main.cpp #include "Stack.h" #include <iostream> using namespace std; class Box { pub ...
- 模板函数(template function)出现编译链接错误(link error)之解析
总的结论: 将template function 或者 template class的完整定义直接放在.h文件中,然后加到要使用这些template function的.cpp文件中. 1. 现 ...
- 用T4 Template生成代码
1 T4语法 T4的语法与ASP.NET的方式比较类似.主要包括指令.文本块.控制块. 1.1 指令 指令主要包括template, output, assembly, import, incl ...
- 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 ...
- 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 ...
- idea: Unable to parse template "class"
使用idea创建文件时,报“Cannot Create Class”.具体错误为: Unable to parse template "Class" error meesage: ...
随机推荐
- Postman Json测试接口
当传递Json数据时: 1.必须添加http头:content-type:application/json,否则会报错(后台取不到相对应的值) 注意:如果服务端只支持UTF-8,但程序未对提交数据进行 ...
- 表或视图不存在 Hibernate Oracle
曾经运行一个别人写的程序,之前连的别人的机器的数据,后来我把数据导入到本地数据库中运行,出错,如下:Hibernate: select sum(rdb_alert_0_.EVENT_COUNT) as ...
- JNI概述
JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++). JNI 让你在利用强大 Java 平台的同时,使你仍然可以用 ...
- python列表和分片
列表的分片 str = " print("打印第0个元素:" ,str[0]) print("负数表示倒数第N个元素,-1表示倒数第一个元素:" ,s ...
- HTML5本地缓存localStorage和sessionStorage的操作方法收集
说明: Web Storage 包含如下两种机制: sessionStorage 为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开 ...
- SHAREPOINT 2013 + PROJECT 2013 资料网站
1.http://technet.microsoft.com/zh-CN/sharepoint 2\ 博客圆专业讲解 http://www.cnblogs.com/jianyus/archive/2 ...
- 使用spice连接kvm guest主机
spice技术已经出来很久了,其是优于VNC的一种远程桌面协议,之所以这里记录下,是由于某些加密视频文件(如以vpy结尾的超时代视频加密),会识别主机的特征吗,一旦主机重启后这些视频又没法查看了,所以 ...
- Java平时需要注意的事项
1.String 相等 稍微有点经验的程序员都会用equals比较而不是用 ==,但用equals就真的安全了吗,看下面的代码 user.getName().equals("xiaoming ...
- spring+mybatis项目启动报错Initializing Spring root WebApplicationContext
这个问题很怪异,各种各样的情况都会导致这个问题的出现,主要是由于sping加载读取配置文件的时候出了问题.我在处理mybatis的时候出现了这个问题,后来排查发现,在mybatis的配置文件中如果有大 ...
- Yii使用公共函数
在网站项目中,没必要把公用的函数写成一个工具类,有时候面向过程其实更方便. 在入口文件index.php里添加 require_once('protected/function.php'); 即可对其 ...