链接有问题

Something wrong with linking

本文关键字:有问题 链接      更新时间:2023-10-16

我有三个c++文件:genericStack.h:

template <class T> 
class Stack{
 public:
  Stack (int size){
    top = -1;
    MAX_SIZE = size;
    v = new T (size);
  }
  ~Stack(){ delete v;}
  T pop();
  void push (T);
  class Underflow{};
  class Overflow{};
  private:
   int top;
   int MAX_SIZE;
   T* v;
 };

genericStackImpl.c + +:

#include "genericStack.h"
template <class T>
void Stack <T> :: push (T c){ 
  if (top == MAX_SIZE - 1) throw Overflow();
  v[++top] = c;
} 
template <class T>
T Stack <T> :: pop(){
  if (top < 0) throw Underflow();
  return v[top--];
}

driver.c + +:

#include <iostream>
#include "genericStack.h"
int main(){
 Stack<char> sc(3);
 try{
   while (true) sc.push ('p');
 }
 catch (Stack<char>::Overflow){std::cout << "Overflow caughtn";}
 try{
  while (true) std::cout << sc.pop() << 'n';
 }
 catch (Stack<char>::Underflow){ std::cout << "Underflow caughtn";}
 return 0;
}

当我使用g++ 4.5编译时:

g++ -o driver driver.c++ genericStackImpl.c++

我得到这些错误:

/tmp/ccLXRXgF.o: In function `main':
driver.c++:(.text+0x2e): undefined reference to `Stack<char>::push(char)'
driver.c++:(.text+0x3c): undefined reference to `Stack<char>::pop()'
collect2: ld returned 1 exit status
我不明白是什么问题。如果我在驱动程序文件中移动实现,那么它将编译并运行。

一般来说,模板定义也需要在头文件中。一个例外是当你显式实例化,或使用显式特化,这两个你都没有做。

解决这个问题的一种方法是将genericStackImpl.c++的内容移到其头文件的底部。

这样做的原因是因为模板函数不是实际的函数,它们只是模板。模板被用来(实例化)创建实际的函数,而这些就是你链接的对象。

genericStackImpl.c++中没有函数。这些函数只有在您使用它们时才会被创建,即编译器第一次看到sc.pushsc.pop时。不幸的是,当driver.c++试图创建这些函数时,它找不到模板体——它们隐藏在genericStackImpl.c++中!相反,它只是编译对这些函数的引用,希望其他文件也能生成它们。

最后,当涉及到链接时间时,链接器在任何地方都找不到该函数,因此它会给您一个错误。

另一种解决这个问题的方法是在genericStackImpl.c++中显式地实例化这些函数,即
template class Stack<char>;

这将创建函数,并且链接器将找到它们。

这种方法的问题是,它要求你事先知道你要在堆栈中使用什么类型,所以大多数人只是把模板定义放在头文件中。