C++学习笔记55——类模板的输入输出操作符

根据重载操作符那一章的规定,输入输出操作符必须作为友元而不是类的成员函数重载。

在类的模板中重载输入输出操作符的方式主要有两种:

  1. 在类模板中做friend声明,在模板外做函数定义;
  2. 在类模板中定义友元操作符;

1,在类外定义友元操作符

1.1 将函数模板设为友元

#include <iostream>
#include <bitset>
using namespace std;

template<int h, int w> class MyScreen
{
public:
	MyScreen() :contents(h*w, '#'), width(w), height(h) {}
	MyScreen(string new_contents) :contents(new_contents), width(w), height(h) {}

	template<int h1, int w1> friend ostream& operator<< (ostream& os, const MyScreen<h1, w1>& ScreenOne);

private:
	int width;
	int height;
	string contents;
};

template<int h2, int w2> ostream& operator <<(ostream &os, const MyScreen<h2, w2> &ScreenOne)
{
	os << "height:" << ScreenOne.height << "\n"
		<< "width:" << ScreenOne.width << "\n"
		<< "contents:" << ScreenOne.contents ;

	return os;
}

int main()
{
	MyScreen<3, 4> ScreenOne("HuangYang Love WHY");
	cout << ScreenOne << endl;

	system("pause");
	return 0;
}

执行结果:


1.2 将函数模板的一个实例设为友元

其他不变,将类模板的定义改为如下形式:
template<int h, int w> class MyScreen
{
public:
	MyScreen() :contents(h*w, '#'), width(w), height(h) {}
	MyScreen(string new_contents) :contents(new_contents), width(w), height(h) {}

	friend ostream& operator<< <h,w> (ostream& os, const MyScreen<h, w>& ScreenOne);

private:
	int width;
	int height;
	string contents;
};
注意,做友元声明的时候,必须跟上模板形参。
因为这里将输出流操作符定义成了一个函数模板,设为友元的仅仅是这个模板的一个实例。
模板形参不可省略。如果将友元声明改成:
friend ostream& operator<< (ostream& os, const MyScreen<h, w>& ScreenOne);

则编译报错。
“fatal error LNK1120: 1 个无法解析的外部命令”
因为此时,在模板外定义重定义的输出流操作符与模板类声明的友元输出流操作符不是同一个操作符。

代码总结如下:
#include <iostream>
#include <bitset>
using namespace std;

template<int h, int w> class MyScreen
{
public:
	MyScreen() :contents(h*w, '#'), width(w), height(h) {}
	MyScreen(string new_contents) :contents(new_contents), width(w), height(h) {}

	// 整个模板设为友元,OK
	template<int h1, int w1> friend ostream& operator<< (ostream& os, const MyScreen<h1, w1>& ScreenOne);

	// 模板的一个实例设为友元,OK
	//friend ostream& operator<< <h,w> (ostream& os, const MyScreen<h, w>& ScreenOne);

	// Error!
	//friend ostream& operator<< (ostream& os, const MyScreen<h, w>& ScreenOne);// Error

private:
	int width;
	int height;
	string contents;
};

template<int h2, int w2> ostream& operator <<(ostream &os, const MyScreen<h2, w2> &ScreenOne)
{
	os << "height:" << ScreenOne.height << "\n"
		<< "width:" << ScreenOne.width << "\n"
		<< "contents:" << ScreenOne.contents ;

	return os;
}

int main()
{
	MyScreen<3, 4> ScreenOne("HuangYang Love WHY");
	cout << ScreenOne << endl;

	system("pause");
	return 0;
}


2,在类内定义友元操作符

template<int h, int w> class MyScreen
{
public:
	MyScreen() :contents(h*w, '#'), width(w), height(h) {}
	MyScreen(string new_contents) :contents(new_contents), width(w), height(h) {}

	//template<int h1, int w1> friend ostream& operator<< (ostream& os, const MyScreen<h1, w1>& ScreenOne)//OK
	//friend ostream& operator<< <h, w> (ostream& os, const MyScreen<h, w>& ScreenOne)//OK
	friend ostream& operator<< (ostream& os, const MyScreen<h, w>& ScreenOne)//OK
	{
		os << "height:" << ScreenOne.height << "\n"
			<< "width:" << ScreenOne.width << "\n"
			<< "contents:" << ScreenOne.contents;

		return os;
	}


private:
	int width;
	int height;
	string contents;
};

int main()
{
	MyScreen<3, 4> ScreenOne("HuangYang Love WHY");
	cout << ScreenOne << endl;

	system("pause");
	return 0;
}

当在类内部定义时,三种声明方式都可以。

3,多文件编译

以上的描述都是针对单文件编译的情况。但是,我们在日常中经常遇到的情况却是多文件编译。
一旦将输出流定义在另外一个文件中时,就会报错。
比如将1.1的例子分成3个文件friend.h、friend.cpp、main.cpp来实现:
friend.h:
#pragma once

#include <iostream>
#include <bitset>
using namespace std;

template<int h, int w> class MyScreen
{
public:
	MyScreen() :contents(h*w, '#'), width(w), height(h) {}
	MyScreen(string new_contents) :contents(new_contents), width(w), height(h) {}

	// 整个模板设为友元
	template<int h1, int w1> friend ostream& operator<< (ostream& os, const MyScreen<h1, w1>& ScreenOne);

private:
	int width;
	int height;
	string contents;
};

friend.cpp:
#include "friend.h"

template<int h2, int w2> ostream& operator <<(ostream &os, const MyScreen<h2, w2> &ScreenOne)
{
	os << "height:" << ScreenOne.height << "\n"
		<< "width:" << ScreenOne.width << "\n"
		<< "contents:" << ScreenOne.contents;

	return os;
}

main.cpp:
#include "friend.h"
int main()
{
	MyScreen<3, 4> ScreenOne("HuangYang Love WHY");
	cout << ScreenOne << endl;

	system("pause");
	return 0;
}

则编译报错:
“fatal error LNK1120: 1 个无法解析的外部命令”

原因没想明白!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值