3

我对 C++ 比较陌生,目前正在使用向量和 ostream 进行分配,以打印出一个包含其他向量的向量。但是,当我尝试运行程序时,我目前收到此错误: symbol not found

operator<<(std::basic_ostream<char, std::char_traits<char> >&, Hash_Table<Entry, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)", referenced from: _main in main.o

这是我的main()代码

int main(){

Hash_Table<Entry,string> newTable(11);


// insert
Entry newEntry;
newEntry.setKey("cat");
newTable.insert(newEntry);

//print Dictionary
cout << "Dictionary contains:";
cout << newTable;

cout << '\n';

    return 0;
}

这是我的Entry课:

class Entry {
public:
Entry();
string getKey();
void setKey(string key);
int getHash(int M);
friend istream& operator>> (istream& in, Entry& right);
friend ostream& operator<< (ostream& out, const Entry& right);

private:

string data;
};

这是我的Hash_Table课:

template <typename T,typename K>
class Hash_Table {
public:
Hash_Table(int size); 
void insert(T newEntry); 
T* search(K key); 
void delete_entry(T* entry);
friend ostream& operator<< (ostream& out, const Hash_Table& right);
private:
vector< vector<T> > hashTable;
};

最后,这是我打印矢量的功能....

template <typename T,typename K>
ostream& operator<< (ostream& out, const Hash_Table<T,K>& right) {
for (int i=0; i < right.hashTable.size(); i++)
    for (int j=0; j < right.hashTable[i].size(); j++) 
        out << "Slot " << i << ", Entry " << j
        << "\n" << right.hashTable[i][j] << "\n\n";
return out;
}

基本上我正在尝试实现一个字典(ADT)。哈希表是向量的向量...到目前为止,一切似乎都有效...但是我无法将向量的内容打印到控制台。我应该要打印出带有cout << newTable;.... 的矢量,但我不断收到此错误。据我了解,我的打印功能应该可以工作......我是否忽略了什么?

4

4 回答 4

3

但是,当我尝试运行程序时,我目前收到此错误:symbol not found

我猜“运行”是指编译,因为这是编译器错误,而不是运行时错误。

问题可能是您在文件中定义了您operator<<.cpp文件,因此编译器看不到它。使用普通的类和函数可以,但使用模板就不行,因为编译器需要在您实例化模板时查看模板定义。

解决方案是将运算符定义放在定义Hash_Table类模板的标头中。您可能会遇到关于Hash_Table.

另一个问题是,正如 Yuushi 所指出的,模板化操作符声明为类的朋友。这是一个口味问题,但如果有另一种解决方案,我通常会完全避免声明朋友函数,并且有:

template <typename T, typename K>
class Hash_Table {
    //....

  void printToStream(std::ostream& os) const {
    //your output algorithm here
  }
};

template <class T, class K>
std::ostream& operator<<(std::ostream& os Hash_Table<T,K> const& ht) {
  ht.printToStream(os);
  return os;
}

声明朋友通常被认为是糟糕的设计,因为它部分破坏了封装,并且比继承更紧密的耦合。虽然朋友的便利性超过了普通函数的紧耦合,这主要是一个品味问题,但在处理模板时,这是一个巨大的封装问题,因为任何人都可以专门化模板:

template <> istream& operator>> <int, std::string> (istream& in, const Hash_Table<int,std::string>& right) 
{
  right.hashTable.resize(1);
  for (unsigned i = 0; i < 2000000; ++i)
    right.hashTable[0].push_back("I just hijacked your Hash_Table implementation!";
} 

这是邪恶但合法的——你把这个功能变成了你的朋友,虽然它可能不那么友好;-)

于 2013-06-11T05:44:41.700 回答
2

这是模板和friend功能烦恼的一部分。当您声明您在模板类中编写友元函数时,编译器实际上并没有识别出该friend函数本身就是一个模板。解决此问题的一种方法是使用成员模板:

template <typename T, typename K>
class Hash_Table
{
    //....

    template <typename T2, typename K2>
    friend ostream& operator<< (ostream& out, const Hash_Table<T2, K2>& right);
};

然后在定义中:

template <typename T, typename K>
ostream& operator<<(ostream& out, const Hash_Table<T, K>& f)
{
    //Code as before
}   

有关更多信息,请参阅此处,尽管被警告,但它可能会让您的头部有些受伤。

于 2013-06-11T05:54:34.063 回答
1

更改您的 Hash_Table 类:

template< typename T, typename K>
class Hash_Table;   // fore declaration

template< typename T, typename K>
ostream&  operaotr<< (ostream& out, Hash_Table<T,K> const& right); //foreward declaration

template <typename T,typename K>
class Hash_Table {
public:
Hash_Table(int size); 
void insert(T newEntry); 
T* search(K key); 
void delete_entry(T* entry);
// change here!!!
friend ostream& operator<< <T,K> (ostream& out, const Hash_Table& right);
private:
vector< vector<T> > hashTable;
};

if operator<< 的实现仍然是您的原始代码。尝试一下,看看是否还有错误。

于 2013-06-11T05:42:40.603 回答
0

让我谈谈类模板的朋友。类模板的朋友可以分为三种:

  1. 普通类和普通函数,没有任何模板
  2. 类模板和函数模板
  3. 专门的类模板和专门的函数模板

有一些例子可以清楚地说明:

template<typename T>
class Exam
{
   friend void normalFunc();
   friend class NormalClass;
};
// nothing happen, it looks straightforward

另一个例子:

template<typename T>
class TemplateClass;
template<typename T>
void FunctionTemplate();

template<typename T>
class Exam
{
    template<typename U>
    friend class TemplateClass; 
    template<typename U>
    friend void FunctionTemplate();
};

这意味着 函数模板“FunctionTemplate”和类模板“TemplateClass”的所有实例都是类模板“Exam”的所有实例的 朋友意味着

  1. TemplateClass<AnyType>是朋友班的 Exam<AnyOtherType>

  2. FunctionTemplate<AnyType>是的朋友函数Exam<AnyOtherType>

注意,AnyType 可以与 AnyOtherType 相同。

这是最有用的示例,这就是您想要的:

    template<typename T>
    class TemplateClass;
    template<typename T>
    void FunctionTemplate();

    template<typename T>
    class Exam
    {

        friend class TemplateClass<T>; 

        friend void FunctionTemplate<T>();
    };

这意味着:

  1. 只有TemplateClass<SpecificType>朋友班的Exam<SpecificType>
  2. 只有FunctionTemplate<SpecificType>是朋友功能Exam<SpecificType>

通过这种方式,您可以更昂贵,当然更安全地授予朋友访问权限!

于 2013-06-11T06:54:58.860 回答