1. 友元
1.1 友元函数
在类体中用friend对该函数进行声明,此函数就称为本类的友元函数
-
将普通函数声明为友元函数
#include<iostream> using namespace std; class Time { public: Time(int, int, int); friend void dispaly(Time &); private: int hour,minute,sec; }; Time::Time(int h, int m, int s) { hour = h; minute = m; sec = s; } void display(Time &t) { cout << t.hour << ":" << t.minute << ":" << t.sec << endl; } int main() { Time t1(1,2,3); display(t1); return 0; }
在这里,dispaly函数是一个在类外定义的且未用类Time限定的函数,它是非成员函数,如果不将这个函数声明为友元函数,则不能引用类中的私有成员。
-
友元成员函数
friend函数不仅可以是一般函数,还可以是另一个类中的成员函数
#include<iostream> using namespace std; class Date; // 对Date类提前引用声明 class Time { public: Time(int, int, int); void display(Date &); // display是成员函数,形参是Date类对象的引用 private: int hour,minute,sec; }; class Date { public: Date(int ,int ,int ); friend void Time::display(Date &); // 声明display为本类的友元成员函数 private: int month,day,year; }; Time::Time(int h, int m, int s) { hour = h; minute = m; sec = s; } void Time::display(Date &d) { cout << d.month << "/" << d.day << "/" << d.year << endl; // 引用Date类对象中的私有数据 cout << hour << ":" << minute << ":" << sec << endl; // 引用本类对象中的私有数据 } Date::Date(int m,int d,int year) { month = m;; day = d; year = y; } int main() { Time t1(1,2,3); Date d1(2,3,2001); t1.display(d1); // 调用t1中的display函数,实参是Date类对象d1 return 0; }
这里有两点需要注意:
- 提前引用声明:只包含类名,不包括类体
- 在Time::函数中引用Date类私有数据必须加上对象名
1.2 友元类
将一个类声明为另一个类的友元,一般在类中的定义体中定义,形式为:friend 类名,这时友元类B中的所有函数都是类A的友元函数,可以访问类A中的所有成员
class A
{
public:
friend B;
};
class B
{
public:
……
};
有两点需要注意:
- 友元关系是单向的。如果声明了B是A的友元类,不等于A是B的友元类
- 友元关系不能传递。如果B是A的友元类,C是B的友元类,不代表C是A的友元类
2. 类模板
对于功能相同而数据类型不同的一些函数,不必一一定义各个函数,可以定义一个可对任何类型变量进行操作的函数模板,再调用函数时,系统会根据实参的类型,取代函数模板中的类型参数,得到具体的函数,这样可以简化程序。下面是一个例子:声明一个类模板,利用它分别实现两个整数、浮点数和字符比较,求出大数和小数
#include <iostream>
using namespace std;
template<class nametype>
class Compare
{
public:
Compare(nametype a, nametype b)
{
x = a; y = b;
}
nametype max()
{
return (x > y) ? x : y;
}
nametype min()
{
return (x < y) ? x : y;
}
private:
nametype x,y;
};
int main()
{
Compare<int> comp1(3,7);
cout << comp1.max() << endl;
cout << comp1.min() << endl;
Compare<float> comp2(14.78, 59.23);
cout << comp2.max() << endl;
cout << comp2.min() << endl;
Compare<char> comp3('a', 'A');
cout << comp3.max() << endl;
cout << comp3.min() << endl;
return 0;
}
通过上面的例子与之前所学类的对比可看到几个不同点:
-
在声明类模板时要加一行template<class 类型参数名>
-
原有的类型名int、float、char等替换成虚拟类型参数名
-
使用类模板定义对象时使用以下形式
- 类模板名 <实际类型名> 对象名
-
如果在类模板外定义成员函数,应写成如下类模板形式:
-
template<class 虚拟类型参数>
-
函数类型 类模板名<虚拟类型参数>::成员函数名(函数形参表列){}
template<class nametype> nametype Compare<nametype>::max() { return (x > y) ? x : y; }
-
-
类模板的参数可以有一个或者多个,每个类型前面都必须加class,在定义对象时分别带入实际的类型名,如下
template<class T1, class T2> class someclass { …… }; someclass<int, double> obj;
3. 习题
-
将友元函数小节中例子代码的display函数不放在Time类中,而作为类外的普通函数,然后分别在Time和Date类中将display声明为友元函数。在主函数中调用display函数,display函数分别引用Time和Date两个类的对象的私有数据,输出年、月、日和时、分、秒。
#include<iostream> using namespace std; class Date; // 对Date类提前引用声明 class Time { public: Time(int, int, int); friend void display(Time &, Date &); // display是成员函数,形参是Date类对象的引用 private: int hour,minute,sec; }; class Date { public: Date(int ,int ,int ); friend void display(Time &, Date &); // 声明display为本类的友元成员函数 private: int month,day,year; }; Time::Time(int h, int m, int s) { hour = h; minute = m; sec = s; } void display(Time &t,Date &d) { cout << d.year << "-" << d.month << "-" << d.day << " "<< t.hour << ":" << t.minute << ":" << t.sec << endl; // 引用Date类对象中的私有数据 } Date::Date(int m,int d,int y) { month = m; day = d; year = y; } int main() { Time t1(19,3,29); Date d1(11,1,2021); display(t1,d1); // 调用t1中的display函数,实参是Date类对象d1 return 0; }
-
将第三题中的Time类声明为Date类的友元类,通过Time类中的display函数引用Date类对象的私有数据,输出年、月、日和时、分、秒
#include<iostream> using namespace std; class Date; // 对Date类提前引用声明 class Time { public: Time(int, int, int); void display(Date &); // display是成员函数,形参是Date类对象的引用 private: int hour,minute,sec; }; class Date { public: Date(int ,int ,int ); friend Time; private: int month,day,year; }; Time::Time(int h, int m, int s) { hour = h; minute = m; sec = s; } void Time::display(Date &d) { cout << d.year << "-" << d.month << "-" << d.day << " "<< hour << ":" << minute << ":" << sec << endl; // 引用Date类对象中的私有数据 } Date::Date(int m,int d,int y) { month = m; day = d; year = y; } int main() { Time t1(19,5,36); Date d1(11,1,2021); t1.display(d1); // 调用t1中的display函数,实参是Date类对象d1 return 0; }
下一章: