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

 1 #include "Stack.h"
 2 
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 class Box {
 8 public:
 9     Box():data(0), ID(num++) { cout << "Box" << ID << " cons" << endl; }
10     Box(const Box &copy): data(copy.data), ID(num++) { cout << "Box" << ID << " copy cons" << endl; }
11     ~Box() { cout << "Box" << ID << " des" << endl; }
12     int data;
13 private:
14     static int num;
15     const int ID;
16 };
17 
18 int Box::num = 1;
19 
20 int main()
21 {
22     Box b1,b2,b3;
23     Stack<Box> bstack;
24     bstack.push(b1);
25     bstack.push(b2);
26     bstack.push(b3);
27     return 0;
28 }

 

Stack.h

 1 #ifndef STACK_H
 2 #define STACK_H
 3 
 4 #include <cstddef>
 5 
 6 template <typename T>
 7 class StackImpl; // Stack implementation (hidden), private part
 8                 // will not be seen by clients
 9 
10 template <typename T>
11 class Stack
12 {
13     public:
14         Stack();
15         ~Stack();
16         /**
17             Inserts a new element at the top of the stack,
18             above its current top element.
19             The content of this new element is
20             initialized to a copy of val.
21             @param val value to which the inserted element is initialized
22         */
23         void push(const T &val);
24         /**
25             @return a reference to the top element in the stack
26         */
27         T& top();
28         /**
29             @return a const reference to the top element in the stack
30         */
31         const T& top() const;
32         /**
33             Removes the element on top of the stack.
34             This calls the removed element's destructor.
35         */
36         void pop();
37         /**
38             @return the number of elements in the stack.
39         */
40         size_t size();
41     private:
42 
43         StackImpl<T> *impl; // Stack implementation (hidden), private part
44                             // will not be seen by clients
45 
46 };
47 
48 #endif // STACK_H

 

Stack.cpp

  1 #include "Stack.h"
  2 
  3 #include <stdexcept>
  4 
  5 using namespace std;
  6 
  7 template <typename T>
  8 class Link {
  9     public:
 10 
 11         T data;
 12         Link *next;
 13 
 14         Link(const T &_data): data(_data), next(NULL) {}
 15         Link(const T &_data, Link *_next): data(_data), next(_next) {}
 16         ~Link() {
 17             next = NULL;
 18         }
 19 
 20 };
 21 
 22 template <typename T>
 23 class StackImpl {
 24     public: // even though they're public, but they're not in the header, thus it's safe
 25 
 26         Link<T> *head;
 27 
 28         size_t size;
 29 
 30         StackImpl(): head(NULL) {}
 31         ~StackImpl() {
 32             Link<T> *ptr = head;
 33             while (ptr != NULL) {
 34                 ptr = head->next;
 35                 delete head;
 36                 head = ptr;
 37             }
 38             size = 0;
 39         }
 40 };
 41 
 42 template <typename T>
 43 Stack<T>::Stack(): impl(new StackImpl<T>()) {}
 44 
 45 template <typename T>
 46 Stack<T>::~Stack() {
 47     if (impl != NULL)
 48         delete impl;
 49 }
 50 /**
 51     Inserts a new element at the top of the stack,
 52     above its current top element.
 53     The content of this new element is
 54     initialized to a copy of val.
 55     @param val value to which the inserted element is initialized
 56 */
 57 template <typename T>
 58 void Stack<T>::push(const T &val)
 59 {
 60     impl->head = new Link<T>(val, impl->head);
 61     ++(impl->size);
 62 }
 63 /**
 64     @return a reference to the top element in the stack
 65 */
 66 template <typename T>
 67 T& Stack<T>::top()
 68 {
 69     if (impl->head == NULL)
 70         throw runtime_error("empty stack");
 71     return impl->head->data;
 72 
 73 }
 74 /**
 75     @return a const reference to the top element in the stack
 76 */
 77 template <typename T>
 78 const T& Stack<T>::top() const
 79 {
 80     if (impl->head == NULL)
 81         throw runtime_error("empty stack");
 82     return impl->head->data;
 83 }
 84 /**
 85     Removes the element on top of the stack.
 86     This calls the removed element's destructor.
 87 */
 88 template <typename T>
 89 void Stack<T>::pop()
 90 {
 91     if (impl->head == NULL)
 92         throw runtime_error("empty stack");
 93     Link<T> *ptr = impl->head->next;
 94     delete impl->head;
 95     impl->head = ptr;
 96     --(impl->size);
 97 }
 98 
 99 /**
100     @return the number of elements in the stack.
101 */
102 template <typename T>
103 size_t Stack<T>::size() {
104     return impl->size;
105 }

 

转载于:https://www.cnblogs.com/qrlozte/p/4108807.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292504.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# using static 声明

许多实际的扩展可以通过扩展方法来实现&#xff0c;并非所有实际的扩展都有可以扩展的类型。对于某些场景&#xff0c;简单的静态方法比较适合。为了更容易调用这些方法&#xff0c;可以使用 using static 声明除去类名。例如&#xff0c;如果打开了 System.Console using stat…

PHP性能追踪及分析工具xhprof的安装与使用

PHP性能追踪及分析工具xhprof的安装与使用 对于本地开发环境来说&#xff0c;进行性能分析xdebug是够用了&#xff0c;但如果是线上环境的话&#xff0c;xdebug消耗较大&#xff0c;配置也不够灵活&#xff0c;因此线上环境建议使用xhprof进行PHP性能追踪及分析。 我们今天就简…

C 语言 int 型乘法溢出问题

2019独角兽企业重金招聘Python工程师标准>>> long l; int a, b; l a*b; 因为 a*b 的结果仍然以 int 型保存, 所以即使 l 为long,仍然会有溢出,并且截去了部分数据.出现问题. 转载于:https://my.oschina.net/simon203/blog/175885

Android插件化开发基础之Java类加载器与双亲委派模型

类加载器 Java虚拟机类加载过程是把Class类文件加载到内存&#xff0c;并对Class文件中的数据进行校验、转换解析和初始化&#xff0c;最终形成可以被虚拟机直接使用的java类型的过程。 在加载阶段&#xff0c;java虚拟机需要完成以下3件事&#xff1a; a.通过一个类的全限定名…

将k8s制作成3D射击游戏,好玩到停不下来,附源码

点击上方蓝字 关注【我的小碗汤】大家好&#xff0c;我是小碗汤&#xff0c;今天演示一个项目&#xff0c;利用Unity做场景、用C#做交互逻辑&#xff0c;将k8s制作成一个3D射击游戏。正好最近在学习Unity&#xff0c;所以利用这个项目开始上手挺合适的。源码、可执行文件可以自…

JavaJVM之ClassLoader源码分析

层次结构和类图 ClassLoader层次结构&#xff1a;UML类图&#xff1a;sun.misc.Launcher.ExtClassLoader sun.misc.Launcher.AppClassLoader 显式加载类 在代码中显式加载某个类&#xff0c;有三种方法&#xff1a;this.getClass().getClassLoader().loadClass()Class.forName(…

ASP.NET Core Web API使用静态swagger.json文件

前言ASP.NET Core Web API默认集成了Swashbuckle&#xff0c;可以在运行时显示Swagger UI&#xff1a;而Swagger UI实际上是解析的动态生成的swagger.json&#xff1a;app.UseSwagger(); app.UseSwaggerUI(c > c.SwaggerEndpoint("/swagger/v1/swagger.json", &qu…

XenApp共享桌面打开文件警告与桌面文件由于Internet文件安全设置无法打开解决办法...

问题现象 1. 在使用了UPM与文件夹重定向后&#xff0c;个人的桌面路径就会变成一个UNC路径&#xff0c;这个时候如果用户登录共享桌面的话可以看到桌面与快速启动栏的文件与快捷方式&#xff0c;但是打开的时候就会遇到以下错误 这种情况是由于我们放的文件是一个网络路径所导致…

周选特辑|一些超棒的开源项目!

编程导航 每周新增资源优选特辑 02编程导航 致力于推荐优质编程资源 &#x1f48e;项目开源仓库&#xff1a;https://github.com/liyupi/code-nav跪求一个 star ⭐️哈喽大家好&#xff01;我是编程导航的小编火宝。美好的一周又过去了&#xff0c;大家有没有认真学习呢&#x…

Android插件化开发之DexClassLoader动态加载dex、jar小Demo

一、温故动态加载ClassLoader机制 如果对Android的ClassLoader加载机制不熟悉&#xff0c;猛戳Android插件化开发动态加载基础之ClassLoader工作机制 http://blog.csdn.net/u011068702/article/details/53248960 二、介绍 我们知道在Android中可以跟java一样实现动态加载jar&…

js监听多个事件_JavaScript中的事件与异常捕获解析

这篇文章主要给大家介绍了关于JavaScript中事件与异常捕获的相关资料&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;写的十分的全面细致&#xff0c;具有一定的参考价值&#xff0c;对此有需要的朋友可以参考学习下。如有不足之处&#xff0c;欢迎批评指正。事件处理…

C#多线程开发-使用并发集合

前言大家好&#xff0c;我是阿辉。在C#语言中当需要处理并发的场景时&#xff0c;就需要程序员使用最合理的数据结构。那么哪些数据结构是支持和可以在并行计算中被使用的呢。首先这些数据结构具备可伸缩性&#xff0c;尽可能地避免锁(会造成多个线程的等待&#xff0c;防止资源…

windows 下安装wamp环境

一直以来都是学习在Linux下安装lanmp环境&#xff0c;在Windows下都是用的集成工具比如appserv现在来安装Windows版本的lamp都是从官网下载的资源在Windows下以后还会编辑更多的东西。我的文章都会以后都有更新&#xff0c;因为有时候有点想法&#xff0c;如果不实践的话会忘记…

应用环境下的TIME_WAIT和CLOSE_WAIT

转载自&#xff1a;http://blog.csdn.net/shootyou/article/details/6622226 昨天解决了一个HttpClient调用错误导致的服务器异常&#xff0c;具体过程如下&#xff1a;http://blog.csdn.net/shootyou/article/details/6615051里头的分析过程有提到&#xff0c;通过查看服务器网…

当社恐和社恐相亲时,场面会有多尴尬?

1 俄国人真实在&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼2 alone和lonely的区别&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 她可能怕她男朋友伤害到别人&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 真正的笋到家了&#xff08;…

FlexPod上安装vSphere 5.5配置中的排错(1)

delxu原创文档&#xff0c;转发请一定要标记本文出处和原文URL。 这些日子在进行FlexPod上的vSphere 5.5的安装和配置&#xff0c;过程中遇到一些故障、困难&#xff0c;都一一解决了。觉得有必要和大家分享一下。可能会有好多篇&#xff0c;也可能和以前一样&#xff0c;虎头蛇…