STL笔记07模板类如何写友元函数,不要滥用!

上来先贴结论:
类模板类外实现不要滥用友元

友元函数

先来复习一下友元函数。

  • 友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend。

问题:

根据友元函数的特性,他是非成员函数;
在模板类中使用友元函数常常会遇到这么一个报错!

无法解析的外部符号

错误代码示例:

#include<iostream>
 
using namespace std;
 
template<class T>
class Person {
public:
	Person(T age, T id);
	friend ostream& operator<<(ostream & os, Person<T> & p);
	void show();

private:
	T mAge;
	T mID;
};
 
int main()
{
	Person<int> p1(1);
	p1.show();
	return 0;
}
 
template<class T>
ostream& operator<<(ostream & os, Person<T> & p)
{
	cout << "age" << p.mAge << "id" << p.mID << endl;
	return os;
}

错误原因:
第一次编译的函数头和第二次编译的函数头不同,

  friend ostream& operator<<(ostream & os, Person<T> & p);
  ostream& operator<<(ostream & os, Person<T> & p);

模板的机制:模板会有二次编译,第一次编译检查类模板或函数模板是否有词法语法等错误,在使用模板函数,编译器会根据实际类型不同生成不同的函数,然后就能找到相应类型的函数体。在实际运用中,模板函数可以利用编译器自动推断类型,可以显式或隐式使用函数模板,类模板必须显式使用,告诉编译器模板类的类型。

友元函数虽然可以访问类内部的成员,但是它相对于类是独立的,它的实现不能依赖类。代码中用到模板类template 而在类内声明友元函数的时候也用到了,所以此时友元函数是依赖于类的实现而实现的,编译器才会报错。

解决方案:

  • 第一种:可以将友元函数的实现放在类的内部
  • 第二种:在类的内部声明友元函数的时候在之前为它单独配一个模板类型,然后在外部实现

友元函数的类内实现

可以将友元函数的实现放在类的内部

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

template<class T>
class Person {
public:
	Person(T age, T id)
	{
		this->mAge = age;
		this->mID = id;
	}
	friend ostream& operator<<(ostream & os, Person<T> & p)
	{
		cout << "age" << p.mAge << "id" << p.mID << endl;
		return os;
	}

	void show()
	{
		cout << "age" << mAge << "id" << mID << endl;
	}

private:
	T mAge;
	T mID;
};

void test01()
{
	Person<int> p(10, 20);
	p.show();
	//cout << p;
	
}
int main()
{
	test01();
	return 0;
}

友元函数的类外实现

在类的内部声明友元函数的时候在之前为它单独配一个模板类型,然后在外部实现

#include<string>
#include<iostream>
using namespace std;
//这里实际上就是先告诉编译器这俩模板不是一回事,友元函数有自己的模板
template<class T>class Person;
template<class T>void print(Person<T>& p);

template<class T>
class Person {
public:
	Person(T age, T id);
	
	friend void print<T>(Person<T>& p);
	void show();

private:
	T mAge;
	T mID;
};


template<class T>
Person<T>::Person(T age, T id)
{
	this->mAge = age;
	this->mID = id;
}


template<class T>
void Person<T>::show()
{
	cout << "age" << mAge << "id" << mID << endl;

}


template<class T>
void print(Person<T>& p)
{

	cout << "print" << p.mAge << p.mID << endl;
}
void test01()
{
	Person<int> p(10, 20);
	//p.show();
	//cout << p;
	print(p);
}
int main()
{
	test01();
	return 0;
}

综上

综上所诉,在模板类中使用友元函数很容易出问题,并且不会直接报错位置,不容易排查,所以不要滥用!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值