0

-- UPDATE --

The problem with the "class type redefinition" seems solved, but the "unresolved externals" is still confusing me. I have used different ways of not reincluding the header file (both #pragma once and using #ifndef/#define, both work), and it's OK. The "unresolved externals" are not related (as far as I can tell). They are relating to a problem I am having with a template defintion. The constructor definition in hashtable.hpp seems correct to me, as does the constructor in hashtable.cpp, but the error I'm getting is:

Severity    Code    Description Project File    Line
Error   LNK2019 unresolved external symbol "public: int __thiscall hashtable<class client,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::search(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?search@?$hashtable@Vclient@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QAEHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "public: void __thiscall clienthash::addrec(class rec *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?addrec@clienthash@@QAEXPAVrec@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)   תרגיל 2 C:\Users\Yael\Desktop\תרגיל 2\תרגיל 2\clienthash.obj    1

which means, if I understand, that the constructor is not found at link time. Anyone?

I've got a file here that's included in 2 different files. When I remove the pragma once, I get an error "class type redefinition", and when I add it I get 10 "unresolved externals" errors. what should I do? here is the file, titled "rec.h" :

#include "item.h"
class rec
{
    string name;
    int grade;
    string description;
public:
    rec(string n, int g, string d) :name(n), grade(g), description(d) {}
    ~rec() {}
};

EDIT: main.cpp:

#include "workerhash.h"
#include "clienthash.h"
#include "rec.h"

void main()
{
    workerhash w(10);
    clienthash c(11);//the same thing will happen
    string n, p, e;
    int num, grade;
    cout << "enter 0 to add a worker, 1 to remove a worker, 2 to add a client, 3 to add a recommendation to a worker, 4 to add a recommender's recommendation, 5 to print a workers details, 6 to print a recommendors reccomendations, and 7 to exit\n";
    cin >> num;
    while(num != 6)
    {
        switch (num)
        {
        case 0:
            cout << "enter name, phone, and email: ";
            cin >> n >> p >> e;
            if (w.search(n) == -1)
                w.insert(worker(n, p, e));
            break;

        case 1:
            cout << "enter worker's name: ";
            cin >> n;
            w.remove(n);
            break;

        case 2:
            cout << "enter name, phone, and email: ";
            cin >> n >> p >> e;
            if (c.search(n) == -1)
                c.insert(client(n, p, e));
            break;

        case 3:
            cout << "enter name of recommendee, grade, and description: ";
            cin >> n >> grade >> p;
            w.addrec(new rec(n, grade, p), n);
            break;
        case 4:
            cout << "enter name of recommender,grade, and description: ";
            cin >> n >> grade >> p;
            c.addrec(new rec(n, grade, p), n);
            break;
        case 5:
            cout << "enter worker's name: ";
            cin >> n;
            grade = w.search(n);//really index, just saving memory
            cout << "name: " << w.wtable.table[grade].data.name << ", phone: " << w.wtable.table[grade].data.phone << ", email: "
                << w.wtable.table[grade].data.email;
            cout << "\n";
        }
    }
}

client.h:

 #pragma once
    #include "rec.h"
    #include <list>
    class client
    {
    public:
        client() {}
        client(string n, string p, string e) :name(n), phone(p), email(e) {}
        ~client() {}
        string name;
        string phone;
        string email;
        list<rec *> l;
    };
clienthash.h:


#include "client.h"
#include "hashtable.h"
class clienthash
{
public:
    clienthash(int size) :ctable(size) {}
    ~clienthash() {}
    hashtable<client, string> ctable;
    void insert(client);
    void remove(string);
    int search (string);
    void addrec(rec *,string);
};

hashtable.h:

#pragma once
#include "item.h"
template<class T, class K>
class hashtable
{
public:
    hashtable(int size);
    ~hashtable();
    item<T,K> * table;
    int size;
    int h1(int & k) {return (k % size);}
    int h1(string & k);
    int h2(int & k) {return (size - (k % size));}
    int h2(string & k);
    int h(int & k,int i) { return ((h1(k) + i*h2(k)) % size);}
    int h(string k, int i) { return ((h1(k) + i*h2(k)) % size); }
    int search(K key);
    void insert(T data, K key);
    void remove(K key);
    void print();
    int prime(int);
    bool isprime(int);
};

item.h:

#pragma once
#include <iostream>
#include <string>
using namespace std;
template<class T,class K>
class item
{
public:
    item():flag(empty),key(NULL){}
    ~item() {}
    T data;
    K key;
    enum state {empty=0,full,del};
    state flag;
};

worker.h:

#pragma once
#include "rec.h"
#include <list>
class worker
{
public:
    worker();
    worker(string n, string p, string e) : name(n), phone(p), email(e) {}
    ~worker();
    string name;
    string phone;
    string email;
    list<rec *> l;
};

workerhash.h:

#include "worker.h"
#include "hashtable.h"

class workerhash
{
public:
    workerhash(int size):wtable(size) {}
    ~workerhash() {}
    hashtable<worker, string> wtable;
    void insert(worker);
    void remove(string);
    int search(string);
    void addrec(rec *, string);
    void print(string);
};

clienthash.cpp:

#include "clienthash.h"
#include <string>

void clienthash::insert(client c)
{
    ctable.insert(c, c.name);
}

void clienthash::remove(string key)
{
    ctable.remove(key);
}

int clienthash::search(string key)
{
    return ctable.search(key);
}

void clienthash::addrec(rec * recommendation, string name)
{
    int index = ctable.search(name);
    if (index != -1)
        (ctable.table[index].data).l.push_back(recommendation);
}

hashtable.cpp:

#pragma once
#include "hashtable.h"
template<class T, class K>
int hashtable<T,K>::prime(int size)
{
    for (int i = size; ; ++i)
        if (isprime(i))
            return i;
}
template<class T, class K>
bool hashtable<T,K>::isprime(int num)
{
    for (int i = 2; i < num; ++i)
        if (num % i == 0 && i != num)
            return false;
    return true;
}
template<class T, class K>
hashtable<T,K>::hashtable(int size)
{
    table = new item[prime(size)];
    this->size = prime(size);
}

template<class T, class K>
hashtable<T,K>::~hashtable()
{
    delete [] table;
    table = NULL;
}

template<class T, class K>
int hashtable<T,K>::search(K key)
{
    for (int i = 0; i < size; ++i)
    {
        if (table[h(key, i)].flag == table[h(key, i)].del && table[h(key, i)].key == key)
            return -1;
        else if (table[h(key, i)].flag == table[h(key, i)].empty)
            return -1;
        else if (table[h(key,i)].key == key)
            return h(key,i);

    }
    return -1;
}

template<class T, class K>
void hashtable<T,K>::insert(T data, K key)
{
    for (int i = 0; i < size; ++i)
        if (table[h(key, i)].flag == table[h(key, i)].empty || table[h(key, i)].flag == table[h(key, i)].del)
        {
            table[h(key,i)].data = data;
            table[h(key, i)].key = key;
            table[h(key, i)].flag = table[h(key, i)].full;
            return ;
        }
}

template<class T, class K>
void hashtable<T,K>::remove(K key)
{
    int index = search(key);
    if (index != -1)
    {
        table[index].flag = table[index].del;
    }
}

template<class T, class K>
void hashtable<T,K>::print()
{
    for (int i = 0; i < size; ++i)
    {
        if (table[i].flag == table[i].empty)
            cout << i << ": empty\n";
        else if (table[i].flag == table[i].del)
            cout << i << ": del\n";
        else cout << i << ": " << table[i].key << "\n";
    }
}
template<class T , class K>
int hashtable<T,K>::h1(string & k) 
{
    unsigned long hash = 5381;
    for (string::iterator it = k.begin(); it != k.end(); ++it) 
        hash = (hash << 5) + hash + int(*it); /* hash * 33 + c */
    return hash;
}
template<class T, class K>
int hashtable<T,K>::h2(string & k)
{
    char *str;

    unsigned long hash = 0;
    int c;

    for (string::iterator it = k.begin(); it!= k.end(); ++it)
        hash = int(*it) + (hash << 6) + (hash << 16) - hash;

    return hash;
}

workerhash.cpp:

#include "workerhash.h"
#include <string>
#include <list>


void workerhash::insert(worker  w)
{
    wtable.insert(w,w.name);
}

void workerhash::remove(string key)
{
    wtable.remove(key);
}

int workerhash::search(string key)
{
    return wtable.search(key);
}

void workerhash::addrec(rec * recommendation, string name)
{
    int index = wtable.search(name);
    if (index != -1)
        wtable.table[index].data.l.push_back(recommendation);
}

void workerhash::print(string name)
{
    int index = wtable.search(name), sum = 0;
    for (list<rec *>::iterator it = wtable.table[index].data.l.begin(); it != wtable.table[index].data.l.end(); ++it)
    {
        //cout<<"recommender: "<<
    }
}

UPDATE:

Well, problem solved.

Thanks ventsyv!

1 Answers1

0

The error you are getting has nothing to do with you include files or header guards because it's a linker error.

I'll truncate the unimportant stuff to make the error more readable:

Error   LNK2019 unresolved external symbol 
public: int __thiscall hashtable::search(class std::basic_string)
referenced in function 
public: void __thiscall clienthash::addrec(class rec *,class std::basic_string)
תרגיל 2 C:\Users\Yael\Desktop\תרגיל 2\תרגיל 2\clienthash.obj    1

Basically, in clienthash::addrec you call hashtable::search(string) but that function is never defined (at least according to the linker).

This is due to the fact that the function is templated and is defined in the .cpp file. C++ has a problem with that (prior to C++11 that is) due to the fact it complies each file separately.

The easiest fix is to move the implementation in the .h file.

If you want more detailed explanation, read this:

https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl

ventsyv
  • 3,316
  • 3
  • 27
  • 49