最近在学习c++的模板,起初还挺顺利,但是在模板类遇到了一个IO流重载的问题
首先我是这样写的,但是不能编译
#include<iostream>
using namespace std;
template<typename T>
class A
{
private:
T c;
public:
A(){}
friend ostream& operator<<(ostream& os, const A &a);
friend istream& operator>>(istream& is, A &a);
};
istream & operator>>(istream& is, A& a) //问题出在这里 编译器提示我
{ //缺少 类模板 "A" 的参数列表 ostream 同理
is >> a.c;
return is;
}
ostream & operator<<(ostream& os, const A& a)
{
os << "a: " << a.c << endl;
return os;
}
int main()
{
A<int> a;
cin >> a;
cout << a;
}
按照编译器的提示 我一步一步改成了这样
template<typename T> // 1
istream & operator>>(istream& is, A<T>& a) //2
{
is >> a.c;
return is;
}
template<typename T> //3
ostream & operator<<(ostream& os, const A<T>& a)//4
{
os << "a: " << a.c << endl;
return os;
}
改了四处地方,编译器不给你看波浪线了,但是还是不能运行,编译运行编译器会给你这样报错
Undefined symbols for architecture x86_64:
“operator<<(std::__1::basic_ostream<char, std::__1::char_traits >&, A const&)”, referenced from:
_main in test-0193fd.o
“operator>>(std::__1::basic_istream<char, std::__1::char_traits >&, A&)”, referenced from:
_main in test-0193fd.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
**
但是,我把函数放在类内部实现
**
#include<iostream>
using namespace std;
template<typename T>
class A
{
private:
T c;
public:
A(){}
friend ostream& operator<<(ostream& os, const A<T> &a)
{
os << "a: " << a.c << endl;
return os;
}
friend istream& operator>>(istream& is, A<T> &a)
{
is >> a.c;
return is;
}
};
int main()
{
A<int> a;
cin >> a;
cout << a;
}
然后我发现了一个BUG
#include<iostream>
using namespace std;
template<typename T>
class A
{
private:
T c;
public:
A(){}
friend ostream& operator<<(ostream& os, const A &a) // 这里删掉了<T>
{
os << "a: " << a.c << endl;
return os;
}
friend istream& operator>>(istream& is, A &a) // 这里也是
{
is >> a.c;
return is;
}
};
int main()
{
A<int> a;
cin >> a;
cout << a;
}
发现这样还是可以正常run,总是感觉不对劲,然后我去翻了一下《C++ Primer Plus》书上明确说明这样写是非法的,因为不存在A这样的对象必须要带上< T > 才合法。
最后说一下如何在类外实现IO流重载
找了好多篇博客发现都没有在类外实现IO流重载
有一篇博客解决了这个问题,作者的思路还是比较奇特,不过确实是解决了问题,给大家参考一下
网上搜到的一种解决方法
但是比较麻烦,我们可以有更简便的方法来实现
#include<iostream>
using namespace std;
template<typename T> class A; //前置声明
template <typename T> ostream & operator<<(ostream &os, const A<T> &a);
template <typename T> istream & operator>>(istream &is, A<T> & a);
template<typename T>
class A
{
private:
T c;
public:
A(){}
friend istream& operator>> <T>(istream& is, A<T> &a);
// 这里要加一个<T>
friend ostream& operator<< <T>(ostream& os, const A<T> &a);
//注意用空格将 <<与<T>隔开
};
template<typename T>
istream & operator>> (istream& is, A<T>& a)
{
is >> a.c;
return is;
}
template<typename T>
ostream & operator<< (ostream& os, const A<T>& a)
{
os << "a: " << a.c << endl;
return os;
}
int main()
{
A<int> a;
cin >> a;
cout << a;
}
这样就完美地在类外实现了IO流重载
所有代码都是在Mac下用vscode进行测试,但是经过我使用其他编译器,以及在Windows下测试所得结果一致,应该不会有太大差别。