几个关键点:

  需要前置声明!--奇怪的是别人告诉我也可以不需要,但我这里不行!

  友元函数的函数名后面的<>,必须要有。

  1. #include <stdio.h>
  2. #include <iostream>
  3. using namespace std;
  4.  
  5. //前置声明,你妹啊
  6. template<class T> class A;
  7. template<class T> ostream &operator<< (ostream &out, const A<T> &_a);
  8. template<class T1, class T2> class B;
  9. template<class T1, class T2> ostream &operator<< (ostream &out, const B<T1, T2> &_b);
  10.  
  11. template<class T> class A
  12. {
  13. public:
  14. A(){}
  15. A(T _a, T _b):a(_a),b(_b){}
  16. ~A(){}
  17. private:
  18. T a;
  19. T b;
  20.  
  21. friend ostream &operator<< <> (ostream &out, const A<T> &a);
  22. };
  23.  
  24. template<class T> ostream &operator<< (ostream &out, const A<T> &_a){
  25. out<<_a.a<<"--"<<_a.b;
  26. return out;
  27. }
  28.  
  29. template<class T1, class T2> class B: public A<T1>
  30. {
  31. public:
  32. B(){}
  33. B(T1 _a, T1 _b, T2 _c):A<T1>(_a,_b),c(_c){} //A<T1>
  34. ~B(){}
  35. private:
  36. T2 c;
  37.  
  38. friend ostream &operator<< <>(ostream &out, const B<T1, T2> &_b);
  39. };
  40. template<class T1, class T2> ostream &operator<< (ostream &out, const B<T1, T2> &_b){
  41. // out<<(A<T1>)_b;
  42. // out<<"--"<<_b.c;
  43.  
  44. out<<(A<T1>)_b<<"--"<<_b.c;
  45. return out;
  46. }
  47.  
  48. int main(int argc, char const *argv[])
  49. {
  50. A<int> x(, );
  51. B<char, int> y('a', 'b', );
  52.  
  53. cout<< x <<endl;
  54. cout<< y <<endl;
  55.  
  56. return ;
  57. }

以上认识太片面,请忽略。

这里 有完美的解释!

大意如下:

模板类的友元其实有多个可能,关键在于这个友元是该模板类的一个/特定具现(实例)的友元,还是所有具现(实例)的友元。

注意1,这里不需要考虑与泛型无关的友元--例如输出一句话之类的,完全没有意义。

注意2,这里的多个可能是编译之前的可能,编译之后还是一个具现(实例)有一个友元(---猜测)。

总之,我认为,这两种仅仅是出发点不同,但最终目的地一致。

一、友元是模板类的一个/特定具现(实例)的友元,需要前置声明:

  1. #include <stdio.h>
  2. #include <iostream>
  3. using namespace std;
  4.  
  5. //前置声明,你妹啊
  6. template<class T> class A;
  7. template<class T> ostream &operator<< (ostream &out, const A<T> &_a);
  8. template<class T1, class T2> class B;
  9. template<class T1, class T2> ostream &operator<< (ostream &out, const B<T1, T2> &_b);
  10.  
  11. template<class T> class A
  12. {
  13. public:
  14. A(){}
  15. A(T _a, T _b):a(_a),b(_b){}
  16. ~A(){}
  17. private:
  18. T a;
  19. T b;
  20.  
  21. friend ostream &operator<< <> (ostream &out, const A<T> &a);
  22. };
  23.  
  24. template<class T> ostream &operator<< (ostream &out, const A<T> &_a){
  25. out<<_a.a<<"--"<<_a.b;
  26. return out;
  27. }
  28.  
  29. int main(int argc, char const *argv[])
  30. {
  31. A<int> x(, );
  32. cout<< x <<endl;
  33.  
  34. return ;
  35. }

二、友元是所有具现(实例)的友元,不需要前置声明:

  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. //友元operator<< 是模板类A的所有实例的友元(实际上还是多个operator<<)--不需要前置声明。
  6. template <typename T>
  7. struct A {
  8. T a;
  9. A(T _a) :a(_a) {}
  10.  
  11. template <typename T1> friend ostream &operator<< (ostream &out, const A<T1> &_a);//这里的T1?? 由于<<输出的是A的实例的对象,所以实际上这里的T1编译之后还是T--因为编译器找不到其他可能。
  12. };
  13.  
  14. template <typename T>
  15. ostream & operator<< (ostream & out, const A<T> &_a) {
  16. out << _a.a;
  17. return out;
  18. }
  19.  
  20. int main() {
  21. A<int> x();
  22. cout << x << endl;
  23.  
  24. return ;
  25. }

C++ 模板类友元之输出流操作符重载的更多相关文章

  1. 15.C++-操作符重载、并实现复数类

    首先回忆下以前学的函数重载 函数重载 函数重载的本质为相互独立的不同函数 通过函数名和函数参数来确定函数调用 无法直接通过函数名得到重载函数的入口地址 函数重载必然发生在同一个作用域中 类中的函数重载 ...

  2. C++中的链表节点用模板类和用普通类来实现的区别

    C++中的链表节点通常情况下类型都是一致的.因此我们可以用模板来实现. #include <iostream> using namespace std; template<typen ...

  3. C++中的操作符重载

    一.什么是操作符重载 操作符重载可以分为两部分:“操作符”和“重载”.说到重载想必都不陌生了吧,这是一种编译时多态,重载实际上可以分为函数重载和操作符重载.运算符重载和函数重载的不同之处在于操作符重载 ...

  4. 15.C++-操作符重载

    首先回忆下以前学的函数重载 函数重载 函数重载的本质为相互独立的不同函数 通过函数名和函数参数来确定函数调用 无法直接通过函数名得到重载函数的入口地址 函数重载必然发生在同一个作用域中 类中的函数重载 ...

  5. C++解析(17):操作符重载

    0.目录 1.操作符重载 2.完善的复数类 3.小结 1.操作符重载 下面的复数解决方案是否可行? 示例1--原有的解决方案: #include <stdio.h> class Compl ...

  6. c++之旅:操作符重载

    操作符重载 操作符重载可以为操作符添加更多的含义,操作符重载的作用的对象是类 那些操作符可以重载 除了下面几个操作符不能重载外,其它的操作符都能重载 . :: .* ?: sizeof 操作符重载的本 ...

  7. 操作符重载(day07)

    二十 操作符重载 eg:复数x+yi +4i (+2i) + (+4i) = +6i 双目操作符(L # R) 1.1 运算类的双目操作符:+ - * / -->左右操作数可以是左值也可以是右值 ...

  8. C++中操作符重载的概念

    1,下面的复数解决方案是否可行? 1,代码示例: class Comples { public: int a; int b; }; int main() { Complex c1 = {, }; Co ...

  9. C#中如何利用操作符重载和转换操作符

    操作符重载 有的编程语言允许一个类型定义操作符应该如何操作类型的实例,比如string类型和int类型都重载了(==)和(+)等操作符,当编译器发现两个int类型的实例使用+操作符的时候,编译器会生成 ...

随机推荐

  1. CXF+Spring+JAXB+Json构建Restful服务

    话不多说,先看详细的样例: 文件文件夹结构: web.xml <?xml version="1.0" encoding="UTF-8"? > < ...

  2. python标准库介绍——14 gc 模块详解

    ==gc 模块== (可选, 2.0 及以后版本) ``gc`` 模块提供了到内建循环垃圾收集器的接口. Python 使用引用记数来跟踪什么时候销毁一个对象; 一个对象的最后一个引用一旦消失, 这个 ...

  3. unity physics joint

    除了unity文档(有点儿过于简略)之外,可以参考一下PhysX文档: http://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/ ...

  4. cocos2dx 3.3将坐标由父空间转化到局部空间

    设在node的父空间内有一点p,要求其转化到node局部空间后的坐标p_local,代码如下: node->getNodeToParentTransform();//in order node- ...

  5. mysql不重启修改参数变量

    分享下mysql不重启的情况下修改参数变量的方法. 通常来说,更新mysql配置my.cnf需要重启mysql才能生效,但是有些时候mysql在线上,不一定允许你重启,这时候应该怎么办呢? 例子: m ...

  6. 无线路由器硬件配置參数 NetGear篇

    NetGear     WNDR4500(号称地球上最强的无线路由器)    450Mbps+450Mbps          京东¥1399 0MHz.配备了128MB的内存和128MB的闪存,再以 ...

  7. [转贴]Cocos2d-x3.2与OpenGL渲染总结(一)Cocos2d-x3.2的渲染流程

    看了opengles有一段时间了,算是了解了一下下.然后,就在基本要决定还是回归cocos2dx 3.2的,看了这篇好文章,欣喜转之~ 推荐看原帖: Cocos2d-x3.2与OpenGL渲染总结(一 ...

  8. C++ 11 Lambda表达式、auto、function、bind、final、override

    接触了cocos2dx 3.0,就必须得看C++ 11了.有分享过帖子:[转帖]漫话C++0x(四) —- function, bind和lambda.其实最后的Lambda没太怎么看懂. 看不懂没关 ...

  9. 我对C++的一些疑问

    我对C++的一些疑问,最近使用C++,总感觉有些东西自己没有抓住,也可能是自己基础学的不是很扎实,所以对一些基本的东西理解不够透彻导致的.因为自己在学校也学过C#和java,C#它是一个完全的面向对象 ...

  10. rzsz安装【转】

    环境:CentOS 发生情况:需要安装工具:szrz 工具进行 windows 和linux传文件 安装方式:从网上其他教程找的所以就按照如下方式操作 1. 下载软件 rzsz-3.34.tar.gz ...