1

I'm trying a controlled, learning experiment with my project and it involves creating my own collections and iterators, essentially an array and a linked list. There is something that I'm missing since it compiles with linking errors. I've spent three days examining, coding and recoding this and I really need some help.

I'm using Visual Studio 2010. I'm dabbling in the new C++11 stuff with the new ranged based for, or for each as I think of it. In Visual C++ it is for each (VAR in LIST), but in GCC it is for (VAR : LIST).

Here is the linker errors:

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)

My code is as follows:

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();
}
Xeo
  • 129,499
  • 52
  • 291
  • 397
Josh Brown
  • 935
  • 1
  • 11
  • 21

4 Answers4

4

Looks to be pretty simple, where is your implementation for your begin and end functions in the Collection class?

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

You have to have a specified implementation for each of these, that is what is causing the linker errors.

radman
  • 17,675
  • 11
  • 42
  • 58
  • Even if it is implemented, it should be together with the declaration, if you put it in a .cpp file, you will still get link errors. Since Container seems to be an abstract container class, it seems better to make those methods pure virtual. – fbafelipe Apr 14 '11 at 04:44
  • Both of those things are true, but he is clearly trying to use the class right now and pointing out that there needs to be an implementation should lead him to thinking about those sort of logistic and design decisions himself. – radman Apr 14 '11 at 04:49
1

for each is Microsoft .NET, eg. managed C++ aka C++/CLI. The real C++11 version is really for(type& var : container).
Next, you got no implementation of your begin and end methods in Container.
Lastly, virtual functions are only in use when using pointers-to-base-types, eg.:

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

Would call the ArrayList<int>::begin() function. Aka, for containers, virtual functions are virtually useless (no pun intended).

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • Visual C++ `for each, in` has all the features of the C++0x range-based for, just with different syntax. See this article: http://msdn.microsoft.com/en-us/library/ms177202(v=VS.100).aspx – Josh Brown Apr 14 '11 at 13:49
1

In the Container class, you should declare begin() and end() as:

virtual Iterator<T> begin() const = 0;
virtual Iterator<T> end() const = 0;
fbafelipe
  • 4,862
  • 2
  • 25
  • 40
  • It is hard to imagine that someone so simple could hold me up for so long. Thank you. My goal was to have that pure virtual on the Container. – Josh Brown Apr 14 '11 at 13:32
1

Whenever a Base class contains non-pure virtual methods, you need to define them somewhere. Otherwise, while creating a Derived class object it will give linker errors such as, undefined reference/symbol. If you don't want to define Container::begin() and Container::end() then declare them as pure virtual.

Here, I have answered a similar question.

Community
  • 1
  • 1
iammilind
  • 68,093
  • 33
  • 169
  • 336