Ошибка компоновщика при использовании шаблонов - PullRequest
1 голос
/ 14 апреля 2011

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

Я использую Visual Studio 2010. Я увлекаюсь новым материалом C ++ 11 с новым ранжированный на основе или для каждого , как я думаю.В Visual C ++ это for each (VAR in LIST), но в GCC это for (VAR : LIST).

Вот ошибки компоновщика:

main.obj : error LNK2001: unresolved external symbol "public: virtual class Iterator<int> __thiscall Container<int>::begin(void)const " (?begin@?$Container@H@@UBE?AV?$Iterator@H@@XZ)
main.obj : error LNK2001: unresolved external symbol "public: virtual class Iterator<int> __thiscall Container<int>::end(void)const " (?end@?$Container@H@@UBE?AV?$Iterator@H@@XZ)

Мой код выглядит следующим образом:

template<typename T>
class Iterator
{
public:
    Iterator(T* Start) : Current(Start) { }
    const T& operator*() const { return *Current; }
    const T* operator->() const { return Current; }
    Iterator<T>& operator++() { Current++; return *this; }
    bool operator!=(Iterator<T> &Other) { return Current != Other.Current; }

protected:
    T* Current;
};

template<typename T>
class Container
{
public:
    Container() : Count(0) { }
    Container(unsigned int Count) : Count(Count) { }

    unsigned int GetCount() const { return Count; }
    bool IsEmpty() const { return Count == 0; }
    Iterator<T>& GetIterator() const { return begin() };

    // Compatibility with C++0x range-based for requires begin() and end() functions.
    virtual Iterator<T> begin() const;
    virtual Iterator<T> end() const;

protected:
    unsigned int Count;
};

template<typename T>
class ArrayList : public Container<T>
{
public:
    ArrayList() : Items(nullptr), Container(0) { }

    virtual Iterator<T> begin() const
    { 
        return Iterator<T>(Items);
    }

    virtual Iterator<T> end() const
    { 
        return Iterator<T>(Items + Count);
    }

private:
    T *Items;
};

int main()
{
    ArrayList<int> MyList;
    for each (auto Item in MyList)
    { }
    return MyList.GetCount();
}

Ответы [ 4 ]

4 голосов
/ 14 апреля 2011

Выглядит довольно просто, где ваша реализация начальных и конечных функций в классе Collection?

virtual Iterator<T> begin() const;
virtual Iterator<T> end() const;

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

1 голос
/ 14 апреля 2011

Всякий раз, когда базовый класс содержит не чистые виртуальные методы, вам нужно их где-то определить. В противном случае при создании объекта класса Derived он выдаст ошибки компоновщика, такие как неопределенная ссылка / символ . Если вы не хотите определять Container::begin() и Container::end(), объявите их как pure virtual.

Здесь я ответил на аналогичный вопрос .

1 голос
/ 14 апреля 2011

В классе Container вы должны объявить begin () и end () как:

virtual Iterator<T> begin() const = 0;
virtual Iterator<T> end() const = 0;
1 голос
/ 14 апреля 2011

for each - это Microsoft .NET, например. управлял C ++, иначе C ++ / CLI. Настоящая версия C ++ 11 действительно for(type& var : container).
Далее, у вас нет реализации ваших begin и end методов в Container.
Наконец, виртуальные функции используются только при использовании указателей на базовые типы , например ::

Container* myCont = new ArrayList<int>();
auto it = myCont->begin();

Будет вызывать функцию ArrayList<int>::begin(). Ака, для контейнеров, виртуальные функции практически бесполезны (не каламбур).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...