为模板类中的>>运算符和<<运算符实现重载
Implementing overloads for >> and << operators in a template class
我正在尝试编写函数定义,以便在类定义之外重载运算符">>"和"<<",尽管在同一个文件中,如您所见。我收到以下错误:
1>Source.obj : error LNK2019: unresolved external symbol "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class MyClass<int> &)" (??5@YAAAV?$basic_istream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$MyClass@H@@@Z) referenced in function _main
1>Source.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class MyClass<int>)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@V?$MyClass@H@@@Z) referenced in function _main
1>Source.obj : error LNK2019: unresolved external symbol "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > &)" (??5@YAAAV?$basic_istream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$MyClass@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@@Z) referenced in function _main
1>Source.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@V?$MyClass@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@@Z) referenced in function _main
我和这个一起在河上上下下。奇怪的是,如果我在类定义中编写他们的定义,它会完美地工作。
#include <iostream>
#include <string>
using namespace std;
template <class MYTYPE>
class MyClass {
MYTYPE *myVector;
int dim;
string name;
public:
MyClass(int, string);
MyClass() {};
friend istream& operator>>(istream&, MyClass<MYTYPE>&);
friend ostream& operator<<(ostream&, MyClass<MYTYPE>);
};
template <class MYTYPE>
MyClass<MYTYPE>::MyClass(int x, string y) {
dim = x;
name = y;
myVector = new MYTYPE[dim];
}
template <class MYTYPE>
istream& operator>>(istream& X, MyClass<MYTYPE>& a){
cout<<"Reading vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++){
cout<<a.name<<'['<<indice<<"]= ";
X >> a.myVector[indice];
}
return X;
}
template <class MYTYPE>
ostream& operator<<(ostream& X, MyClass<MYTYPE> a){
X<<"Vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++)
X<<a.myVector[indice]<<' ';
X<<endl;
return X;
}
int main() {
MyClass<int> object(4, "Ints vector");
MyClass<string> object2(5, "String vector");
cin >> object;
cin >> object2;
cout << object;
cout << object2;
system("pause");
return 0;
}
在您的代码中,MyClass
中的友元运算符声明应如下所示:
template<typename T> friend istream& operator>>(istream&, MyClass<T>&);
template<typename T> friend ostream& operator<<(ostream&, MyClass<T>);
也就是说,它们应具有自己的模板参数。
基于问题中提供的定义,MyClass
的有效定义如下:
template <class MYTYPE>
class MyClass {
MYTYPE *myVector;
int dim;
string name;
public:
MyClass(int, string);
MyClass() {}
template<typename T>
friend istream& operator>>(istream&, MyClass<T>&);
template<typename T>
friend ostream& operator<<(ostream&, MyClass<T>);
};
打开编译器的警告级别会有所帮助。通过将-Wall
与g++
一起使用,我在链接器错误之前收到以下警告。
socc.cc:13:58: warning: friend declaration ‘std::istream& operator>>(std::istream&, MyClass<MYTYPE>& )’ declares a non-template function [-Wnon-template-friend]
friend istream& operator>>(istream&, MyClass<MYTYPE>&);
^
socc.cc:13:58: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
socc.cc:14:57: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, MyClass<MYTYPE> ’ declares a non-template function [-Wnon-template-friend]
friend ostream& operator<<(ostream&, MyClass<MYTYPE>);
您需要对operator>>
和operator<<
函数使用函数模板。您可以在类的定义之前声明它们:
// Forward the class template.
template <class MYTYPE> class MyClass;
// Declare the function templates.
template <class MYTYPE>
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);
template <class MYTYPE>
std::ostream& operator<<(st::ostream&, MyClass<MYTYPE>);
然后,必须将 friend
声明与相应的模板参数一起使用。
// This makes sure that operator>><int> is not a friend of MyClass<double>
// Only operator>><double> is a friend of MyClass<double>
friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);
这是为我构建的代码的更新版本。我还没有尝试运行它。
#include <iostream>
#include <string>
using namespace std;
template <class MYTYPE> class MyClass;
template <class MYTYPE>
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);
template <class MYTYPE>
std::ostream& operator<<(std::ostream&, MyClass<MYTYPE>);
template <class MYTYPE>
class MyClass {
MYTYPE *myVector;
int dim;
string name;
public:
MyClass(int, string);
MyClass() {};
friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);
};
template <class MYTYPE>
MyClass<MYTYPE>::MyClass(int x, string y) {
dim = x;
name = y;
myVector = new MYTYPE[dim];
}
template <class MYTYPE>
std::istream& operator>>(std::istream& X, MyClass<MYTYPE>& a){
cout<<"Reading vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++){
cout<<a.name<<'['<<indice<<"]= ";
X >> a.myVector[indice];
}
return X;
}
template <class MYTYPE>
std::ostream& operator<<(std::ostream& X, MyClass<MYTYPE> a){
X<<"Vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++)
X<<a.myVector[indice]<<' ';
X<<endl;
return X;
}
int main() {
MyClass<int> object(4, "Ints vector");
MyClass<string> object2(5, "String vector");
cin >> object;
cin >> object2;
cout << object;
cout << object2;
system("pause");
return 0;
}
这有点复杂。实际上,类模板有两种方式可以拥有函数友元。
例如,以这个为例:
template <typename T>
void fun();
template <typename T>
class A
{
};
那你想要什么?
- 或者你想让
func<X>()
成为A<Y>
的朋友,Y
? - 你想让
fun<X>()
成为A<X>
的朋友而不是A<Y>
的朋友吗?
也就是说,函数是否应该能够访问任何专用化的私有成员,还是只能访问相同类型的专用化。
我的猜测是您需要选项 2。诀窍是你必须成为函数专用化的朋友,所以模板函数必须已经存在:你首先声明了模板函数,然后让它成为朋友。像这样:
//first declare both function and class
template <typename T>
class A;
template <typename T>
void fun();
//Then define the class
template <typename T>
class A
{
//A<T> is friend to fun<T>, the specializations must match.
friend void fun<T>();
};
//And define the function
template <typename T>
void fun()
{
}
如果您想要的是选项 1,则不需要高级声明。只:
template <typename T>
class A
{
//A<T> is friend to fun<X>, T and X may be different
template <class X>
friend void fun();
};
也就是说,由于<<
和>>
,您的代码编写起来有点棘手:
template <class MYTYPE>
class MyClass;
template <class MYTYPE>
istream& operator>>(istream& X, MyClass<MYTYPE>& a);
template <class MYTYPE>
ostream& operator<<(ostream&, MyClass<MYTYPE>);
template <class MYTYPE>
class MyClass {
// ....
friend istream& operator>> <MYTYPE>(istream&, MyClass<MYTYPE>&);
friend ostream& operator<< <MYTYPE>(ostream&, MyClass<MYTYPE>);
};
相关文章:
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 如何显式调用运算符<<
- 为什么COUT在朋友函数中不起作用,该功能超载了操作员&lt;&lt;这是一个iStream运算符
- C++运算符<<调用::ostream而不是std::osttream
- BOOST ::变体无法解决运算符&lt;&lt;对于STD :: Ostream
- 过载输出<<用于类的运算符,以打印其中的元组
- C++ostream:没有运算符匹配<<&应在'&'代币
- 重载运算符<<:此运算符函数的参数太多
- C++继承运算符<<
- 重载运算符<<用于模板类.即使使用好友关键字也无法获得私人会员
- 如何过载<<用于YAML::Emitter的运算符,以序列化包含另一个自定义类的向量的自定义类
- 为什么字符串流运算符<<擦除原始值
- 关于使用运算符<<为新手提供C++中的模板
- 我已经完成了<<运算符重载,但它'It’不起作用
- 重载运算符<<输出地址而不是数据成员
- 错误:没有匹配'运算符<<"在'std::cout
- 重载运算符<<用于ostream语法
- 当运算符<存在时,为什么要定义 LT?
- log4cxx访问异常,使用<<运算符和宏
- 重载<<运算符错误C2804:二进制'运算符<<'参数太多