Что-то не так со ссылками - PullRequest
       25

Что-то не так со ссылками

1 голос
/ 26 сентября 2011

У меня есть 3 файла 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 caught\n";}
 try{
  while (true) std::cout << sc.pop() << '\n';
 }
 catch (Stack<char>::Underflow){ std::cout << "Underflow caught\n";}
 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

Я не понимаю, в чем проблема. Если я перенесу реализацию в файл драйвера, он скомпилируется и запустится.

1 Ответ

3 голосов
/ 26 сентября 2011

Вообще говоря, определения шаблонов также должны быть в заголовочном файле.Исключением является случай, когда вы явно создаете экземпляр или используете явные специализации, чего вы не делаете.

Один из способов решить эту проблему - переместить содержимое genericStackImpl.c++ в конец его заголовка.файл.

Причина этого в том, что функции шаблонов не являются реальными функциями, они просто шаблоны.Шаблон используется (создается) для создания актуальных функций, и это то, на что вы ссылаетесь.

В genericStackImpl.c++ нет функций.Функции создаются только после их использования, то есть когда компилятор впервые видит sc.push и sc.pop.К сожалению, когда driver.c++ пытается создать эти функции, он не может найти тела шаблона - они скрыты в genericStackImpl.c++!Вместо этого он просто компилирует ссылку на эти функции, надеясь, что их создаст какой-то другой файл.

Наконец, когда дело доходит до времени ссылки, компоновщик нигде не может найти функцию, поэтому он дает вамошибка.

Другим способом решения этой проблемы было бы явное создание экземпляров этих функций самостоятельно в genericStackImpl.c++, то есть

template class Stack<char>;

Это создаст функции, и компоновщик найдет их.

Проблема этого подхода в том, что он требует от вас заранее знать, какие типы вы собираетесь использовать в стеке, поэтому большинство людей просто помещают определения шаблонов в заголовочный файл.

...