在同一个CPP中,使用友元函数,同时在类外实现,这里.h .cpp未分离,如果分离写法不一样。
一般在使用类模板时,将声明和实现放在同一文件中,可命名为.hpp后缀,即.h .cpp在同一文件中
1.重载操作符
定义一个类,通过重载<< 打印输出该类的成员;
方法1,、
在类中声明该函数,同时前面加上 template <class T1, class T2>
template <class T1, class T2>
friend std::ostream& operator<<(std::ostream& os, Person<T1, T2>& p);
方法2:
1)类内写完frien语句后,需要在类外声明本类并且声明友元函数。
2)在friend的语句中加上<>。
//在类外进行前置声明
template <class T1, class T2> std::ostream& operator<<(std::ostream& os, Person<T1, T2>& p);
在friend的语句中 << 后 加上<T1,T2>
friend std::ostream& operator<<<T1,T2>(std::ostream& os, Person<T1, T2>& p);
完整程序如下:
#include <iostream>
using namespace std;
//在类外进行前置声明
// 友元函数在类外面实现,并且都在同一个CPP文件中,
//需要在前面对类和对应操作符重载函数进行前置声明。
// 同时在类内部声明的对应函数需要在参数链表前加入 "<T>"。
template <class T1, class T2> class Person;
template <class T1, class T2> std::ostream& operator<<(std::ostream& os, Person<T1, T2>& p);
//类模板 类外实现
//类模板
template <class T1, class T2>
class Person {
public:
//模板类中使用友元
//重载左移操作符,用于直接打印输出
//方法1
//template <class T1, class T2> //定要加 这句,不过这样的写法在linux不能通过
//friend std::ostream& operator<<(std::ostream& os, Person<T1, T2>& p);
//方法2在操作符后加 <T1,T2>,同时进行类前置声明
//方法1 在VS中可以便宜,但 要在Linux下会出错
friend std::ostream& operator<<<T1,T2>(std::ostream& os, Person<T1, T2>& p);
Person(T1 id, T2 age);
void showPerson();
private:
T1 mId_;
T2 mAge_;
};
//声明和实现分开时,我们需要对函数的声明做特殊处理,
//注意,这里类名应是Person<T1,T2>
template <class T1, class T2>
Person<T1, T2>::Person(T1 id, T2 age) {
this->mAge_ = age;
this->mId_ = id;
}
template <class T1, class T2> void Person<T1, T2>::showPerson() {
std::cout << "id.....:" << mId_ << ",age:" << mAge_ << std::endl;
}
//通过重载左移操作符,用于直接打印输出
template <class T1, class T2>
std::ostream& operator<<(std::ostream& os, Person<T1, T2>& p) {
std::cout << "operator--- id: " << p.mId_ << ",age:" << p.mAge_ << std::endl;
return os;
}
//类模板在类外实现时,不要滥用友元
void testShow() {
//函数模板在调用时,可以自动进行类型推导
//类模板必须显式声明
Person<int, int> person(12, 11111);
//person.showPerson();
std::cout << "ddd: " << person << std::endl;
}
int main() {
testShow();
return 0;
}
2.使用普通友元函数
使用普通友元函数与上面的操作符重载,是同样的操作方法,
完成程序如下:
#include <iostream>
using namespace std;
//方法2 在类外进行前置声明
template <class T1, class T2> class Person;
template <class T1, class T2> std::ostream& operator<<(std::ostream& os, Person<T1, T2>& p);
//类模板 类外实现
//类模板
template <class T1, class T2>
class Person {
public:
//使用普通友元函数进行类外输出
//方法1
//template <class T1, class T2>
//friend void printPerson(Person<T1, T2>& p);
//方法2
//应推荐的写法,把类进行前置声明
friend void printPerson<T1,T2>(Person<T1, T2>& p);
Person(T1 id, T2 age);
void showPerson();
private:
T1 mId_;
T2 mAge_;
};
//声明和实现分开时,我们需要对函数的声明做特殊处理,
//注意,这里类名应是Person<T1,T2>
template <class T1, class T2>
Person<T1, T2>::Person(T1 id, T2 age) {
this->mAge_ = age;
this->mId_ = id;
}
template <class T1, class T2> void
Person<T1, T2>::showPerson() {
std::cout << "id.....:" << mId_ << ",age:" << mAge_ << std::endl;
}
template <class T1, class T2>
void printPerson(Person<T1, T2>& p) {
std::cout << "printPerson, id: " << p.mId_ << ",age:" << p.mAge_ << std::endl;
}
//类模板在类外实现时,不要滥用友元
void testShow() {
//函数模板在调用时,可以自动进行类型推导
//类模板必须显式声明
Person<int, int> person(12, 11111);
printPerson(person);
}
int main() {
testShow();
return 0;
}