zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    [转]Greenplum的工作负载及资源管理
    [转]Tomcat中的Session小结
    [转]Class.forName()的作用与使用总结
    [转]如何在 Git 里撤销(几乎)任何操作
    [转]session和cookie的区别和联系,session的生命周期,多个服务部署时session管理
    piwik获取访客头像,自定义显示访问者头像(URL)和描述(标题和替代)
    php解析url并得到url中的参数及获取url参数
    php结合phantomjs实现网页截屏、抓取js渲染的页面
    利用PhantomJS进行网页截屏,完美解决截取高度的问题
    多线程编程
  • 原文地址:https://www.cnblogs.com/qrlozte/p/4108807.html
Copyright © 2011-2022 走看看