类模板语法知识体系梳理(包含大量常犯错误demo,尤其滥用友元函

demo 1

#include <iostream>#include <cstdio>using namespace std;//template <typename T>class Complex{friend ostream &operator << (ostream &out, Complex &c2);public:Complex(int a, int b) : a(a), b(b) {}Complex operator + (Complex &c2){Complex tem(a + c2.a, b + c2.b);return tem;}void printCom(){cout << a << " + " << b << "i\n";}private:int a;int b;};ostream &operator << (ostream &out, Complex &c2){out << c2.a << " + " << c2.b << "i\n";return out;}int main(){Complex c1(1, 2);c1.printCom();Complex c2(3, 4);c2.printCom(); Complex c3 = c1 + c2;c3.printCom();cout << c3 << endl;return 0;}上述是一个简单的复数类,并重载了+运算符和 << 运算符。

下面拓展,变成模板类:

demo 2

#include <iostream>#include <cstdio>using namespace std;template <typename T>class Complex{friend Complex& mySub(Complex &c1, Complex &c2) // 写在里面没什么问题{Complex tmp(c1.a – c2.a, c1.b – c2.b);return tmp;}friend ostream &operator << (ostream &out, Complex &c2){out << c2.a << " + " << c2.b << "i\n";return out;}public:Complex(T a, T b) : a(a), b(b) {}Complex operator + (Complex &c2){Complex tem(a + c2.a, b + c2.b);return tem;}void printCom(){cout << a << " + " << b << "i\n";}private:T a;T b;};// 运算符重载的正规写法// 重载 << >> 只能用友元函数,其他运算符重载都要写成成员函数,不要滥用友元函数/* 这部分定义必须写进类的内部ostream &operator << (ostream &out, Complex &c2){out << c2.a << " + " << c2.b << "i\n";return out;}*/int main(){// 需要把模板类具体化之后才能定义对象,C++编译器需要分配内存Complex<int> c1(1, 2);c1.printCom();Complex<int> c2(3, 4);c2.printCom(); Complex<int> c3 = c1 + c2;c3.printCom();cout << c3 << endl;// 滥用友元函数{Complex<int> c3 = mySub(c1, c2);cout << c3;}return 0;}这样看起来问题也不大。

继续,把所有成员函数都放到类外部,先还是写在同一个cpp文件中:demo 3

#include <iostream>#include <cstdio>using namespace std;template <typename T>class Complex; // 解决mySub友元函数的滥用template <typename T>Complex<T> mySub(Complex<T> &c1, Complex<T> &c2); // 解决mySub友元函数的滥用template <typename T>class Complex{// 这个友元函数是滥用friend Complex<T> mySub<T>(Complex<T> &c1, Complex<T> &c2); // 写在里面没什么问题// 这样55行会报错//friend ostream &operator << (ostream &out, Complex &c2);// 解决方案friend ostream &operator << <T> (ostream &out, Complex &c2);public:Complex(T a, T b);Complex operator + (Complex &c2);void printCom();private:T a;T b;};// 构造函数拿到写在类的外部template <typename T>Complex<T>::Complex(T a, T b){this->a = a;this->b = b;}template <typename T>void Complex<T>::printCom(){cout << a << " + " << b << "i\n";}// 注意函数参数和函数返回值都需要进行类型具体化template <typename T>Complex<T> Complex<T>::operator + (Complex<T> &c2){Complex tem(a + c2.a, b + c2.b);return tem;}// 报错的本质:模版是两次编译运行的,第一次生成的函数头和第二次生成的函数头不一样// 友元函数实现 << 运算符重载template <typename T>ostream &operator << (ostream &out, Complex<T> &c2){out << c2.a << " + " << c2.b << "i\n";return out;}// 报错/*1>templateComplex2.obj : error LNK2019: 无法解析的外部符号 "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> >&,class Complex<int> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$Complex@H@@@Z),该符号在函数 _main 中被引用*///////////////////////////////////////////////////////// 滥用友元函数template <typename T>Complex<T> mySub(Complex<T> &c1, Complex<T> &c2){Complex<T> tmp(c1.a – c2.a, c1.b – c2.b);return tmp;}// 报错。。。。。。// 解决方案,做前置声明int main(){// 需要把模板类具体化之后才能定义对象,C++编译器需要分配内存Complex<int> c1(1, 2);c1.printCom();Complex<int> c2(3, 4);c2.printCom();Complex<int> c3 = c1 + c2;c3.printCom();cout << c3 << endl;// 滥用友元函数{Complex<int> c3 = mySub(c1, c2);cout << c3;}return 0;}demo 3出现了几个错误,代码中都注释了,尤其友元函数的滥用一定要注意,千万别再不能用友元函数的地方用友元函数,demo 3中出现的问题还都解决了,可是当把类写到.cpp和.h文件中还会出现新的问题,先总结在同一文件下:

所有的类模板函数写在类的外部,在一个cpp中

幸福就是重复。每天跟自己喜欢的人一起,通电话,

类模板语法知识体系梳理(包含大量常犯错误demo,尤其滥用友元函

相关文章:

你感兴趣的文章:

标签云: