错误:E:\Qt Project\test02\main.cpp:3048: error: undefined reference to `listsavitch::operator<<(std::ostream&, listsavitch::GenericList<int> const&)”
E:\Qt Project\test02\main.cpp:3055: error: undefined reference to `listsavitch::operator<<(std::ostream&, listsavitch::GenericList<char> const&)”
这种错误该怎么解决呢?友元函数是不能定义模板吗?还有一个警告,说是在头文件定义的不是一个模板函数。
E:\Qt Project\test02\main.cpp:3055: error: undefined reference to `listsavitch::operator<<(std::ostream&, listsavitch::GenericList<char> const&)”
这种错误该怎么解决呢?友元函数是不能定义模板吗?还有一个警告,说是在头文件定义的不是一个模板函数。
//接口文件 genericlist.h #ifndef GENERICLIST_H #define GENERICLIST_H #include <iostream> using namespace std; namespace listsavitch { template <class ItemType> class GenericList { public: GenericList(int max); ~GenericList(); int length() const; bool full() const; void add(ItemType new_item); void erase(); friend ostream& operator<<(ostream& outs, const GenericList<ItemType>& the_list); //问题出现在这里 private: ItemType *item; int max_length; int current_length; }; } //end listsavitch #endif // GENERICLIST_H #ifndef GENERICLIST_CPP #define GENERICLIST_CPP //实现文件 genericlist.cpp #include <iostream> #include <cstdlib> #include "genericlist.h" using namespace std; namespace listsavitch { template <class ItemType> GenericList<ItemType>::GenericList(int max) :max_length(max), current_length(0) { item = new ItemType[max]; } template <class ItemType> GenericList<ItemType>::~GenericList() { delete [] item; } template <class ItemType> int GenericList<ItemType>:: length() const { return current_length; } template <class ItemType> bool GenericList<ItemType>:: full() const { return (max_length == current_length); } template <class ItemType> void GenericList<ItemType>:: add(ItemType new_item) { if(full()) { cout << "Error: Adding to a full list.\n"; exit(1); } else { item[current_length] = new_item; current_length++; } } template <class ItemType> void GenericList<ItemType>:: erase() { current_length = 0; } template <class ItemType> ostream& operator <<(ostream& outs,const GenericList<ItemType>& the_list) //问题出现在这里 { for (int i = 0; i < the_list.current_length; i++) outs << the_list.item[i] << endl; return outs; } } #endif //GENERICLIST_CPP //应用程序 main.cpp #include <iostream> #include "genericlist.h" #include "genericlist.cpp" using namespace std; using namespace listsavitch; int main () { GenericList<int> first_list(2); first_list.add(3); first_list.add(4); cout << "first_list = \n"; cout << first_list ; //问题出现在这里,重载了操作符<<,但是没办法定义函数GenericList<int> & the_list GenericList<char> second_list(10); second_list.add("a"); second_list.add("b"); second_list.add("c"); cout << "second_list = \n"; cout << second_list; return 0; }
解决方案
5
解决办法:
genericlist.h中修改如下:
friend ostream& operator<< <ItemType>(ostream& outs, const GenericList<ItemType>& the_list);
模板是两次编译生成的,第一次生成的函数头和第二次生成的函数头不一样则报错。
只有在重载<<, >> 时,才使用友元函数,其他情况友元+模板,很复杂,禁止滥用友元函数。
genericlist.h中修改如下:
friend ostream& operator<< <ItemType>(ostream& outs, const GenericList<ItemType>& the_list);
模板是两次编译生成的,第一次生成的函数头和第二次生成的函数头不一样则报错。
只有在重载<<, >> 时,才使用友元函数,其他情况友元+模板,很复杂,禁止滥用友元函数。
10
本人记得有三个办法
1)不在外部定义友元函数,友元函数定义在 类的内部,原因是友元是类的接口。
这种方式最简洁。
1)不在外部定义友元函数,友元函数定义在 类的内部,原因是友元是类的接口。
这种方式最简洁。
template <typename ItemType> class GenericList{ friend ostream& operator<<(ostream& outs, const GenericList& the_list){ // .... return os; }; };
2)类模板内部,声明友元模板函数,类外定义
这样唯一的缺陷是,全部友元模板函数,都是每个模板类的友元函数。
形成多对多友元,而不是一对一友元,
应用上没问题,逻辑上有问题
代码也比较简单,不如第一种方法简洁
template <typename T> class GenericList{ //友元声明为模板函数 template <U> friend ostream& operator<<(ostream& outs, const GenericList<U>& the_list); }; template < ItemType> friend ostream& operator<<(ostream& outs, const GenericList< ItemType>& the_list){ // .... return os; };
3)类内声明友元,类外实现,
需要 类模板GenericList 和operator<< 都前置声明
代码最复杂,不过满足了两个要求
3.1)类定义,和实现代码分离//仅仅是代码分离,不能分离编译
3.2)友元函数和模板类,是一对一关系,一个友元函数,对应一个模板类,逻辑正确。
// a)模板类类前置声明: template <typename ItemType> class GenericList; //b)模板函数 operator<< 前置声明 : template <typename U> ostream& operator<< (ostream& outs, const GenericList<U>& the_list); //类定义 template <typename ItemType> class GenericList { public: /// 。 //c) 友元函数是模板函数的特化,在模板类中,这么写: //注意 friend ostream& operator<< <> //(ostream& outs, //const GenericList& the_list); 注意GenericList& friend ostream& operator<< <>(ostream& outs, const GenericList& the_list); }; //类的实现部分:可分离编写 //d) 友元函数实现代码 template <class ItemType> ostream& operator <<(ostream& outs,const GenericList<ItemType>& the_list) //没问题 { for (int i = 0; i < the_list.current_length; i++) outs << the_list.item[i] << endl; return outs; }
5
你非要这样写,那就点开本人给的链接,里面写的很清楚,关于产生这种问题的原因和解决方案。
本人的意思是,既然不能分开编译,那么写的时候干脆合并在一起就好了,就像那个链接最后那段代码一样,反而会方便一些。