关于C++模板类运算符重载在类内外实现的不同

最近在学习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下测试所得结果一致,应该不会有太大差别。

上一篇:GPLT L2-018 多项式A除以多项式B 多项式除法


下一篇:018把所做的变成热爱,做热爱的事而不做上瘾的事