1

I am working on a program for school. It is a link list using templates.

I have an abstract base class:

#pragma once
#include <string>

using namespace std;

template<class T>
class LinkedListInterface
{

public:

    LinkedListInterface(void){};
    virtual ~LinkedListInterface(void){};


    virtual void insertHead(T value) = 0;


    virtual void insertTail(T value) = 0;


    virtual void insertAfter(T value, T insertionNode) = 0;


    virtual void remove(T value) = 0;


    virtual void clear() = 0;


    virtual T at(int index) = 0;


    virtual int size() = 0;

};

And a class I derived from it:

/* Linklist.h
 *
 *  Created on: Oct 4, 2014
  *   
  */

 #ifndef LINKLIST_H_
 #define LINKLIST_H_

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

 template<class T>
 class Linklist: public LinkedListInterface<T> {
 private:
     struct _node
         {
           T val;
           Linklist *next;
         };
         struct _node node ;
        Linklist *root = NULL;
        Linklist *tail = NULL;
        int _size = 0;
        int finddup(T value);
 public:
    Linklist();
    virtual ~Linklist();


     void insertHead(T value);
      void insertTail(T value);


         void insertAfter(T value, T insertionNode);


         void remove(T value);


         void clear();


         T at(int index);


         int size();

 };

 #endif /* LINKLIST_H_ */

Linklist.cpp

 /*
  * Linklist.cpp
  *
  *  Created on: Oct 4, 2014
  *      
  */

 #include "Linklist.h"

 template<class T>
 Linklist<T>::Linklist()
 {
    // TODO Auto-generated constructor stub

 }

 template<class T>
 Linklist<T>::~Linklist()
 {
    // TODO Auto-generated destructor stub
 }

 template<class T>
 int Linklist<T>::finddup(T value)
 {
    Linklist *tmp = root;

    while (tmp)
    {
        if (tmp->node.val == value)
        {
            return 1;
        }
    }

    return 0;
 }


 template<class T>
 void Linklist<T>::insertHead(T value)
 {
    Linklist *tmp = root;

    if (finddup(value))
    {
        return;
    }
    else
    {
        if (!root)
        {
            root = new Linklist<T>();
            root->val = value;
            root->next = NULL;
            tail = root;
            _size++;
        }
        else
        {
            Linklist *newr = new Linklist<T>();
            newr->node.val = value;
            newr->node.next = root;
            root = &newr;
            _size++;
        }
    }

 }


 template<class T>
 void Linklist<T>::insertTail(T value)
 {
    Linklist *tmp = root;

    if (finddup(value))
    {
        return;
    }
    else
    {
        if (!tail)
        {
            tail = new Linklist<T>();
            tail->val = value;
            tail->next = NULL;
            root = tail;
            _size++;
        }
        else
        {
            Linklist *newr = new Linklist<T>();
            newr->node.val = value;
            newr->node.next = NULL;
            tail->node.next = &newr;
            tail = &newr;
            _size++;
        }
    }

 }


 template<class T>
 void Linklist<T>::insertAfter(T value, T insertionNode)
 {

    if (finddup(value))
    {
        return;
    }
    else
    {
        Linklist *tmp = root;
        while (tmp)
        {
            if (tmp->node.val == insertionNode)
            {
                Linklist *newr = new Linklist<T>();
                newr->node.val = value;
                 newr->node.next = tmp->node.next;
                 tmp->node.next = &newr;
                 _size++;
                 break;
             }
             else
                 tmp = tmp->node.next;
         }
     }
 }


 template<class T>
 void Linklist<T>::remove(T value)
 {
    Linklist *prev = NULL, *active = NULL;

    if (!root)
        std::cout << "List is empty" << std::endl;
    else
    {
         if (root && root->node.val == value)
         {
             Linklist *t = root;
             root = t->node.next;
             delete t;
             _size--;
         }
     }
     prev = root;
     active = root->node.next;
     while (active)
     {
         if (active->node.val == value)
         {
             prev->node.next = active->node.next;
             delete active;
             _size--;
             active = prev->node.next;
         }
         else
        {
            prev = active;
             active = active->node.next;
         }
     }

 }


 template<class T>
 void Linklist<T>::clear()
 {
     Linklist *t = root;
     while (t)
     {
         t = root->node.next;
         delete root;
         root = t;
     }
     root = NULL;
     tail = NULL;
     _size = 0;

 }


 template<class T>
 T Linklist<T>::at(int index)
 {
    Linklist *t = root;

     if (index < _size)
     {
         for (int i = 0; i < _size; i++)
         {
             t = t->node.next;
         }
     }
     else
     {
         t = NULL;
     }

     return (t);

 }


 template<class T>
 int Linklist<T>::size()
 {
     return (_size);
 }

Those seem to be ok. The problem is when I try to create a Linklist object in a factory class that was provided and I modified.

 #include "Factory.h"

 #include "Linklist.h"



 //You may add #include statements here

 /*

     You will MODIFY THIS DOCUMENT.

 */

 /*

     getLinkedListInt() and

     Creates and returns an object whose class extends LinkedListInterface.

     This should be an object of a class you have created.

     Example: If you made a class called "LinkedList", you might say, "return new      LinkedList<int>();".

 */

 LinkedListInterface<int> * Factory::getLinkedListInt()
 {

     return new Linklist<int>();

 }



 /*
     getLinkedListString() and

     Creates and returns an object whose class extends LinkedListInterface.

     This should be an object of a class you have created.

     Example: If you made a class called "LinkedList", you might say, "return new LinkedList<string>();".

 */

 LinkedListInterface<string>* Factory::getLinkedListString()
 {

     return new Linklist<string>();

 }

I am told:

 undefined reference to `Linklist<int>::Linklist()'

 undefined reference to `Linklist<string>::Linklist()'

When I compile. I don't understand templates well enough to know what I messed up on.

Does anyone have any advice?

Thanks

Niall
  • 30,036
  • 10
  • 99
  • 142
  • http://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix – Cory Kramer Oct 06 '14 at 20:05

1 Answers1

0

This is not going to work:

main.cpp

#include "Source.h"

int main() {
    Linklist<int> obj;
}

Source.h

#pragma once

template <class T>
class Linklist {
public:
    Linklist();
};

Source.cpp

#include "Source.h"

template <class T>
Linklist<T>::Linklist() {}

Output:

error LNK2019: unresolved external symbol "public: __cdecl Linklist::Linklist(void)"

this happens because of how templates are instantiated.

In your specific case you can either explicitly instantiate the int and string types or you can change the design in order to have declaration and definition in your header file.

For more info: Why can templates only be implemented in the header file?

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246