c ++ paradox,添加/删除标题保护

时间:2015-07-30 20:53:27

标签: c++

- 更新 -

“类型重新定义”的问题似乎已经解决,但“未解决的外部”仍然让我感到困惑。我已经使用了不同方法来重新包含头文件(#pragma一次和使用#ifndef / #define,两者都工作),这没关系。 “未解决的外部”与此无关(据我所知)。它们与我遇到的模板定义问题有关。 hashtable.hpp中的构造函数定义对我来说似乎是正确的,hashtable.cpp中的构造函数也是如此,但我得到的错误是:

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

这意味着,如果我理解,在链接时找不到构造函数。任何人吗?

我这里有一个文件,包含在2个不同的文件中。当我删除一次编译指示时,我得到一个错误“类类型重新定义”,当我添加它时,我得到10个“未解析的外部”错误。我该怎么办?这是一个名为“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() {}
};

编辑: 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: "<<
    }
}

更新:

嗯,问题解决了。

谢谢ventsyv!

1 个答案:

答案 0 :(得分:0)

您获得的错误与包含文件或标题保护无关,因为它是链接器错误。

我会截断不重要的东西,使错误更具可读性:

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

基本上,在clienthash :: addrec中你调用hashtable :: search(string),但是从不定义该函数(至少根据链接器)。

这是因为该函数是模板化的并且在.cpp文件中定义。 C ++有一个问题(在C ++ 11之前),因为它分别符合每个文件。

最简单的解决方法是在.h文件中移动实现。

如果您需要更详细的说明,请阅读:

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