Ошибка дублированного символа g ++ при работе с шаблонами (вопрос noob) - PullRequest
3 голосов
/ 23 июля 2010

Итак, я пытаюсь выбрать C ++, и для этого я решил написать общий класс Group с использованием шаблонов, который принимает тип и размер в качестве параметров шаблона:

в group.h:

#ifndef __GROUP_H
#define __GROUP_H
#define MAX_SIZE 10

/**********************************************************
 * Define a Group class that handles a collection of members
 * of some Type
 **********************************************************/
template <class Type, int max>
class Group {
  private:
      std::string name;
      int count, size;
      Type * members[max];

  public:
      Group();
      Group(const std::string & _name);
      ~Group();

      // display instance info
      virtual void show();

      // add member
      void add_member(Type &);

      // list memebers
      void list();

      // name setter/getter
      void set_name(const std::string &);
      const std::string & get_name();

};

#endif

group.cc:

/**********************************************************
 * class methods for Group
 **********************************************************/
template <class Type, int max>
Group<Type, max>::Group() : count(0), size(max), name("New Group") {};

template <class Type, int max>
Group<Type, max>::Group(const std::string & _name) : name(_name), count(0), size(max) {};

template <class Type, int max>
Group<Type, max>::~Group() {
  int i = 0; 
  while(i < this->count) {
    delete this->members[i];
    ++i;
  }
}

template <class Type, int max>
void Group<Type, max>::show() {
    std::cout << "<#Group - Name: " << this->name << ", Members: " << this->count << "/" << this->size << " >\n";
}

template <class Type, int max>
void Group<Type, max>::add_member(Type & member) {
    if (this->count < this->size) {
        this->members[this->count] = &member;
        this->count++;
    } else {
        std::cout << "Error - this Group is full!\n";
    }
}

template <class Type, int max>
void Group<Type, max>::list() {
    int i = 0;
    std::cout << "The following are members of the Group " << this->name <<":\n";
    // assumes the member has a show() method implemented
    while (i < this->count) {
        std::cout << i << ". ";
        (this->members[i])->show();
        ++i;
    }
}

template <class Type, int max>
void Group<Type, max>::set_name(const std::string & _name) {
    this->name = _name;
}

template <class Type, int max>
const std::string & Group<Type, max>::get_name() {
  return this->name;
}

Я также реализовал класс Person и класс Employee (который наследуется от Person), и оба работают и имеют метод show ().

Моя главная выглядит так:

test.cc

#include <iostream>
#include "group.h" // this also has the declarations and implementation for Person/Employee

int main (int argc, char const *argv[])
{
    // Person ctor takes name and age
    Person p1("John", 25); 
    Person p2("Jim", 29);

    // Group takes name to init
    Group <Person, 5> g("Ozcorp");
    g.add_member(p1);
    g.add_member(p2);
    g.list();    
}

Я скомпилировал его с помощью простого Makefile:

test: test.cc group.o
    g++ -o test test.cc group.o

group.o: group.h group.cc
    g++ -c group.cc

И наконец (вот так), когда я запустил его с ./test, появились следующие ошибки:

Undefined symbols:
  "Group<Person, 5>::list()", referenced from:
      _main in ccaLjrRC.o
  "Group<Person, 5>::Group(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)", referenced from:
      groups()    in ccaLjrRC.o
      _main in ccaLjrRC.o
  "Group<Person, 5>::~Group()", referenced from:
      groups()    in ccaLjrRC.o
      _main in ccaLjrRC.o
      _main in ccaLjrRC.o
  "Group<Person, 5>::add_member(Person&)", referenced from:
      _main in ccaLjrRC.o
      _main in ccaLjrRC.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [test] Error 1

Если бы вы зашли так далеко - спасибо - и я был бы признателен за понимание того, почему это происходит. Я пытался поделиться как можно больше из кода (очевидно), так что простите меня, если это слишком много. Исходный код был скомпилирован с g ++ 4.2.1 на Mac OSX 10.6.4. Также будут оценены любые советы по стилю / хорошим навыкам кодирования. Спасибо!

Ответы [ 3 ]

6 голосов
/ 23 июля 2010

Шаблонное определение члена класса не попадает в файлы .cc / .cpp. Они идут в .h или в файле .hpp / .hxx, включенном в .h Рациональным является то, что файлы .cc / .cpp используются для создания файлов объектов. Однако с помощью шаблонного кода объекты нельзя создавать до замены шаблонных аргументов. Следовательно, их реализация должна быть доступна для всех фрагментов кода, создающих их экземпляры: в файле .h как.

3 голосов
/ 23 июля 2010

Создание шаблона может быть неявным (выполняется компилятором) или явным (запрашивается пользователем). Для неявных реализаций компилятор должен видеть определение функции шаблона в месте вызова - что, как уже сказал Филипп, - проще всего сделать, добавив определения функции шаблона в файл заголовка.

Альтернатива каким-то образом ограничена: если вы знаете все экземпляры вашего шаблона заранее, вы можете оставить определения функций шаблона в другом месте и явно их создать. В вашем случае в конце group.cpp вы можете добавить:

template class Group<Person, 5>;

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

Если сомневаетесь, предоставьте определения в заголовочном файле и помните, что определения функций должны быть встроены, иначе вы столкнетесь с ошибкой компоновщика: «дублированный символ», если вы включаете заголовок из разных единиц перевода. Функция-член встроена по умолчанию, если она определена в фигурных скобках класса или если она имеет ключевое слово inline.

3 голосов
/ 23 июля 2010

Компилятор должен видеть определения шаблонов, если он хочет их создать. Самый простой способ добиться этого - поместить каждый фрагмент шаблонного кода (включая все определения) в заголовочный файл.

...