1

いくつかの問題に遭遇しながら、単純なデータ構造ライブラリを作成しています。

3つのファイルを書きました。collections.h はヘッダー ファイル、collections.cpp はヘッダー ファイルで宣言されたメソッドを実装するため、main.cpp はテスト用です。しかし、コンパイルエラーが発生します:

List::GetCount() const への未定義の参照。

List::IsEmpty() const への未定義の参照。

List::Add(int); への未定義の参照;

...// 等々。

以下にコードを提供します。どこに問題がありますか?

コレクション.h:

#ifndef COLLECTIONS_H
#define COLLECTIONS_H

#include <windows.h>
#include <stdexcept>

template<typename T>
class ISequenceList
{
protected:
    ISequenceList() { }
public:
    virtual int GetCount() const = 0;
    virtual bool IsEmpty() const = 0;
    virtual void Add(T item) = 0;
    virtual void AddRange(const T *items, int length) = 0;
    virtual T &ElementAt(int index);
    virtual bool InsertAt(T item, int index);
    virtual bool Remove(T item) = 0;
    virtual bool RemoveAt(int index) = 0;
    virtual bool Contains(T item) = 0;
};

template<typename T>
class List : public ISequenceList<T>
{
private:
    int _count;
    int _capacity;
    T *_array;

    void ExpandCapacity();
public:
    List(int capacity = 100)
    {
        if (capacity <= 0)
            std::__throw_invalid_argument("The capcity can't be 0 or below.");
        this->_count = 0;
        this->_capacity = capacity;
        this->_array = (T*)malloc(_capacity* sizeof(T));
    }
    List(const List &other)
    {
        if (this == other)
            return;
        this->_count = other->_count;
        this->_capacity = other->_capacity;
        free(_array);
        this->_array = other->_array;
    }
    List &operator=(const List &other)
    {
        this = other;
    }
    ~List()
    {
        if (_array)
            free(_array);
    }

    int GetCount() const;
    bool IsEmpty() const;
    T &ElementAt(int index);
    void Add(T item);
    void AddRange(const T *items, int length);
    bool InsertAt(T item, int index);
    bool Remove(T item);
    bool RemoveAt(int index);
    bool Contains(T item);
};

#endif

コレクション.cpp:

#include "collections.h"

template<typename T>
void List<T>::ExpandCapacity()
{
    T *temp = this->_array;
    this->_array = (T*)malloc((this->_capacity << 1) * sizeof(T));
    memcpy(this->_array, temp, this->_capacity * sizeof(T));
    this->_capacity = this->_capacity << 1;
    free(temp);
}

template<typename T>
int List<T>::GetCount() const
{
    return this->_count;
}

template<typename T>
bool List<T>::IsEmpty() const
{
    return this->_count == 0;
}

template<typename T>
void List<T>::Add(T item)
{
    this->_array[_count] = item;
    _count++;
    if (_count == _capacity)
        this->ExpandCapacity();
}

template<typename T>
void List<T>::AddRange(const T *items, int length)
{
    if (length <= 0)
        std::__throw_invalid_argument("The length can't be 0 or below.");
    if (!items)
        std::__throw_invalid_argument("The items can't be null");
    int totalLength = this->_count + length;
    if (totalLength >= this->_capacity)
    {
        T *temp = this->_array;
        this->_array = (T*)malloc((totalLength << 1) * sizeof(T));
        memcpy(_array, temp, this->_capacity);
        free(temp);
    }
    this->_array += this->_capacity;
    memcpy(_array, items, length * sizeof(T));
    this->_capacity = totalLength << 1;
    this->_count += length;
}

template<typename T>
T &List<T>::ElementAt(int index)
{
    if (index < 0 || index >= _count )
        std::__throw_invalid_argument("The index is out of bound.");
    return _array[index];
}

template<typename T>
bool List<T>::InsertAt(T item, int index)
{
    if (index < 0 || index > _count)
        return false;
    if (index == _count)
    {
        this->Add(item);
        return true;
    }
    for (int i = _count; i > index; i--)
    {
        _array[i] = _array[i - 1];
    }
    _array[index] = item;
    _count++;
    if (_count == _capacity)
        this->ExpandCapacity();
    return true;
}

template<typename T>
bool List<T>::Remove(T item)
{
    for (int i = 0; i < _count; i++)
    {
        if (_array[i] == item)
        {
            for (int j = i; j < _count; j++)
            {
                _array[j] = _array[j + 1];
            }
            _count--;
            return true;
        }
    }
    return false;
}

template<typename T>
bool List<T>::RemoveAt(int index)
{
    if (index < 0 || index >= _count)
        return false;
    for (int j = index; j < _count; j++)
    {
        _array[j] = _array[j + 1];
    }
    _count--;
    return true;
}

template<typename T>
bool List<T>::Contains(T item)
{
    for (int i = 0; i < _count; i++)
    {
        if (_array[i] == item)
            return true;
    }
    return false;
}

main.cpp:

#include "collections.h"
#include <iostream>

int main()
{
    List<int> *seqList = new List<int>();
    seqList->Add(5);
    int arr[100] = {0};
    seqList->AddRange(arr, 50);
    seqList->ElementAt(5) = 111;
    seqList->InsertAt(100, 15);
    seqList->Remove(50);
    seqList->ElementAt(44) = 44;
    seqList->RemoveAt(44);
    if (seqList->Contains(111))
        std::cout << "Yes" << std::endl;

    for (int i = 0; i < seqList->GetCount(); i++)
    {
        std::cout << seqList->ElementAt(i) << "\t";
    }

    return 0;
}

List ですべてのメソッドを定義しましたが、コンパイラが認識できないのはなぜですか? 問題はどこだ?私を助けてくれてありがとう..

注: 私のアイデアは Code::Blocks です

4

1 に答える 1

4

テンプレート関数の実装はヘッダーにある必要があります。別のソース ファイルにすることはできません。コンパイラは、テンプレートが使用され、その引数が認識される時点でそれを確認する必要があります。

于 2013-09-12T16:25:12.373 に答える