mercredi 21 juillet 2021

C++ Derived Class with template, constructor undefined

Well, i'm trying to build a project in c++ but I got an undefined error while I'm using a template for a derived class:

The project are defined as the following:

|_bin 
|_include
|    |_Items.h
|    |_Lists.h
|_src
     |_main.cpp
     |_lists.cpp
     |_items.cpp

The code:

Items.h

#ifndef ITEMS_H
#define ITEMS_H

#include <iostream>
using namespace std;

namespace Lists {
    template <class T>
    class LinkedList;
}

namespace Items {

    template <class T>
    class Item {
        public: 
            Item() = default;
            Item(T id);
            void SetId(T id) { this->id = id; }
            T GetId() { return this->id; }
            virtual void Print() const {};
        protected:   
            T id;
    };
    
    template <class T>
    class ItemConsciousness: public Item<T> {
        public: 
            ItemConsciousness() = default;
            ItemConsciousness(T id): Item<T>(id) {};
            ItemConsciousness(T id, string data, string msg);
            void SetData(string data) {this->data = data;}
            string GetData() { return this->data; }
            void SetMsg(string msg) {this->msg = msg;}
            string GetMsg() { return this->msg; }
            void Print();
        
        private: 
            string data;
            string msg;
    };

    template <class T>
    class Node {
        public:
            Node() = default;
            Node(Item<T> item, Node* next);
        private: 
            Item<T> item;
            Node* prox;
        friend class Lists::LinkedList<T>;
    };
    
}
#endif

Items.cpp

#include "Items.h"

#include <iostream>

using namespace Items;
using namespace std;

template <class T>
Item<T>::Item(T id){
    this->id = id;
}

template <class T>
ItemConsciousness<T>::ItemConsciousness(T id, string data, string msg) {
    this->SetId(id);
    this->SetData(data);
    this->SetMsg(msg);
};


template <class T>
void ItemConsciousness<T>::Print() { 
    cout << this->data << " " << this->msg << endl; 
}


template <class T>
Node<T>::Node(Item<T> item, Node* next){
    this->item = item;
    this->next = next;
}

Lists.h

#ifndef LISTS_H
#define LISTS_H


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

using namespace std;
using namespace Items;

namespace Lists { 
    template<class T> 
    class List {
        public:
            List() {this->size = 0;};
            int GetSize() {return size;};
            bool IsEmpty() {return size == 0;};

            virtual Item<T> GetItem(int pos) = 0;
            virtual void SetItem(Item<T>, int pos) = 0;
            virtual void InsertStart(Item<T> item) = 0;
            virtual void InsertEnd(Item<T> item) = 0;
            virtual void InsertPosition(Item<T> item, int pos) = 0;
            virtual Item<T> RemoveStart() = 0;
            virtual Item<T> RemoveEnd() = 0;
            virtual Item<T> RemovePosition(int pos) = 0;
            virtual Item<T> Search(T c) = 0;
            virtual void Print() = 0;
            virtual void Clear() = 0;
        protected:
            int size;
    };

    template<class T> 
    class LinkedList: public List<T> {
        private: 
            Node<T>* first;
            Node<T>* last;
            Node<T>* Position(int pos, bool is_before = false);
            
        public: 
            LinkedList();
            ~LinkedList();
            Item<T> GetItem(int pos);
            void SetItem(Item<T> item, int pos);
            void InsertStart(Item<T> item);
            void InsertEnd(Item<T> item);
            void InsertPosition(Item<T> item, int pos);
            Item<T> RemoveStart();
            Item<T> RemoveEnd();
            Item<T> RemovePosition(int pos);
            Item<T> Search(T c);
            void Print();
            void Clear();
    };
}
#endif

Lists.cpp


#include "Lists.h"
#include "Items.h"

#include <iostream>

using namespace Items;
using namespace Lists;
using namespace std;

template<class T>
LinkedList<T>::LinkedList()  { // O(1)
    this->size = 0;
    first = new Node<T>();
    last = first;
}

template<class T>
LinkedList<T>::~LinkedList() {  // O(n)
    this->Clear(); 
    delete this->first;
}


template<class T>
void LinkedList<T>::Clear() { // O(n)
    Node<T> *p;

    p = this->first->next;
    while(p!=NULL) {
        this->first->next = p->next;
        delete p;
        p = this->first->next;
    }
    this->last = this->first;
    this->size = 0;
}


template<class T>
Node<T>* LinkedList<T>::Position(int pos, bool is_before) { // Best Case O(1) and Worse O(n)
    Node<T>* p; 
    int i;

    if((pos > this->size) || (pos <= 0)){
        throw "ERROR: Invalid Position!";
    }
    p = this->first;
    for(i=1; i<pos; i++) {
        p = p->next;
    }

    if(!is_before) {
        p = p->next;
    }
    return p;
}

template<class T>
Item<T> LinkedList<T>::GetItem(int pos) {  // Best Case O(1) and Worse O(n)
    Node<T>* p;

    p=this->Position(pos);
    return p->item;
}

template<class T>
void LinkedList<T>::SetItem(Item<T> item, int pos) {// Best Case O(1) and Worse O(n)
    Node<T>* p;

    p = this->Position(pos);
    p->item = item;
}

template<class T>
void LinkedList<T>::InsertStart(Item<T> item) { // Custo O(1)
    Node<T>* new_node;

    new_node = new Node<T>();
    new_node->item = item;
    new_node->next = this->first->next;
    this->first->next = new_node;
    this->size++;

    if (new_node->next == NULL) {
        this->last = new_node;
    }
};

template<class T>
void LinkedList<T>::InsertEnd(Item<T> item) { // Custo O(1)
    Node<T>* new_node;

    new_node = new Node<T>();
    new_node->item = item;
    this->last->next = new_node;
    this->last = new_node;
    this->size++;
};

template<class T>
void LinkedList<T>::InsertPosition(Item<T> item, int pos) {// Best Case O(1) and Worse O(n)
    Node<T>* p, *new_node;

    p = Position(pos, true);

    new_node = new Node<T>();
    new_node->item = item;
    new_node->next = p->next;
    p->next = new_node;
    this->size++;

    if (new_node->next == NULL) {
        this->last = new_node;
    }
}

template<class T>
Item<T> LinkedList<T>::RemoveStart() { // O(1)
    Item<T> aux;
    Node<T>* p;

    if(this->size== 0) {
        throw "ERROR: Empty List!";
    }

    p = this->first->next;
    this->first->next = p->next;
    this->size--;
    if(this->first->next == NULL) {
        this->last = this->first;
    }
    aux = p->item;
    delete p;
    return aux;
}

template<class T>
Item<T> LinkedList<T>::RemoveEnd() { // O(n)
    Item<T> aux;
    Node<T>* p;

    if (this->size == 0) {
        throw "ERROR: Empty List!";
    }

    p = this->Position(this->size, true);

    p->next = NULL;
    this->size--;
    aux = last->item;
    delete last;
    this->last = p;

    return aux;
}

template<class T>
Item<T> LinkedList<T>::RemovePosition(int pos) { // Best: O(1), Worse: O(n)
    
    Item<T> aux;
    Node<T> *p, *q;

    if(this->size ==0)
        throw "ERROR: Empty List!";

    p = this->Position(pos, true);
    q = p->next;
    p->next = q->next;
    this->size--;
    aux = q->item;
    delete q;
    if (p->next == NULL) {
        this->last = p;
    }
    return aux;
}

template<class T>
Item<T> LinkedList<T>::Search(T c) { // Best: O(1), Worse: O(n)
    Item<T> aux;
    Node<T>* p;

    if(this->size == 0) {
        throw "ERROR: Empty List!";
    }

    p = this->first->next;
    aux.SetChave(-1);
    while(p!=NULL) {
        if(p->item.GetId() == c) {
            aux = p->item;
            break;
        }
        p=p->next;
    }
    return aux;
}

template<class T>
void LinkedList<T>::Print() { // O(n)
    Node<T>* p;
    p = this->first->next;
    while(p!=NULL) {
        p->item.Print();
        p = p->next;
    }
};

main.cpp

#include <iostream>
#include "Items.h"
#include "Lists.h"

using namespace std;
using namespace Items;
using namespace Lists;


int main() {
    int num_servers;
    cin >> num_servers;

    LinkedList<int> server_buffer;
   
    Item<int> i;
    ItemConsciousness<int> user1;

    Node<int> n;
}

Command to compile and run:

g++ -Wall -Wextra -std=c++11 -ggdb -Iinclude -Llib src/Lists.cpp src/Items.cpp src/main.cpp -o bin/main

The error that I got:


/usr/bin/ld: /tmp/ccu3TkFa.o: in function `main':
/mnt/c/Users/lauro/VERLAB/src/main.cpp:16: undefined reference to `Lists::LinkedList<int>::LinkedList()'
/usr/bin/ld: /mnt/c/Users/lauro/VERLAB/src/main.cpp:16: undefined reference to `Lists::LinkedList<int>::~LinkedList()'
/usr/bin/ld: /mnt/c/Users/lauro/VERLAB/src/main.cpp:16: undefined reference to `Lists::LinkedList<int>::~LinkedList()'
collect2: error: ld returned 1 exit status
make: *** [Makefile:20: bin/main] Error 1
The terminal process "bash '-c', 'bash -c 'make run''" terminated with exit code: 2.

I don't know why these errors are occurring...

And a interesting point is that, if a change the main.cpp to:

#include <iostream>
#include "Items.h"
#include "Lists.h"

using namespace std;
using namespace Items;
using namespace Lists;


int main() {
    int num_servers;
    cin >> num_servers;

    LinkedList<int> server_buffer();
   
    Item<int> i;
    ItemConsciousness<int> user1;

    Node<int> n;
}

The code runs perfectly without any errors.

Aucun commentaire:

Enregistrer un commentaire