友元的作用:在不改变数据安全性的前提下,使得类外部的函数或者另一个类能够访问该类中的私有数据成员。
三种形式:
(1)友元函数
(2)友元成员
(3)友元类
一、友元函数
定义:将一个不属于任何类的普通函数定义为当前类的友元,成为当前类的友元函数
原型声明:friend 函数返回类型 函数名(形式参数表)
例如:我们需要一个Equal函数来比较两个Date类的对象是否相等
Date.h
#ifndef DATE_H
#define DATE_H
class Date
{
private:
int year;
int month;
int day;
public:
Date(int ,int ,int );
~Date();
int GetYear();
int GetMonth();
int GetDay();
friend bool Equal(Date &,Date &);///将在Equal函数声明为Date的友元函数
};
#endif // DATE_H
Date.cpp
#include "Date.h"
Date::Date(int y,int m,int d)
{
year=y;
month=m;
day=d;
}
Date::~Date()
{
//dtor
}
int Date::GetYear()///在类外实现的时候竟然又忘记了加 类名:: ,还是练得少啊
{
return year;
}
int Date::GetMonth()
{
return month;
}
int Date::GetDay()
{
return day;
}
main.cpp
#include <iostream>
#include"Date.h"
using namespace std;
bool Equal(Date &DateA,Date &DateB)
{
///因为Equal已经声明为Date类的友元函数,Date类的对象不需要通过成员函数就能直接访问数据成员
if(DateA.year==DateB.year&&DateA.month==DateB.month&&DateA.day==DateB.day)
return true;
else return false;
}
int main()
{
Date YourBirthday(1990,10,7);
Date MyBirthday(1990,10,7);
if(Equal(YourBirthday,MyBirthday))///比较两个对象是否相同
cout<<"Birthday is the same"<<endl;
else
cout<<"Birthday is not the same"<<endl;
return 0;
}
二、友元成员函数
定义:一个类的成员函数作为另一个类的友元,成为另一个类的友元成员。
作用:不仅可以访问自己所在类的数据成员,也可以访问friend声明语句所在类的所有成员
例子:将Date类的成员函数Display声明为Student类的友元函数(同时说明了类的声明,类的实现,main函数可以写在同一个.cpp文件中)
#include<iostream>
#include<cstring>
using namespace std;
class Student; ///向前引用,为什么不同通过先后定义的顺序来解决呢?因为Date类和Student类你中有我,我中有你
class Date
{
private:
int year;
int month;
int day;
public:
Date(int y=2007,int m=1,int d=1);
void Display(const Student &);///成员函数,形式参数为Student的对象的引用
};
class Student
{
private:
char *specialty;
public:
Student(char *pSpec);
~Student();
friend void Date::Display(const Student &);///将Date类中的成员函数Display声明为Student类的友元函数
};
Date::Date(int y,int m,int d)
{
year=y;
month=m;
day=d;
cout<<"Constructor Called"<<endl;
}
void Date::Display(const Student &stu)
{
cout<<stu.specialty<<endl;
cout<<year<<"-"<<month<<"-"<<day<<endl;///因为Date::Display为Student的友元函数,所以可直接使用Student中的数据成员
}
Student::Student(char *pSpec)///pSpec接收 定义对象时传的实参的地址
{
if(pSpec)///数据成员的赋值
{
specialty=new char[strlen(pSpec)+1];
strcpy(specialty,pSpec);
}
else specialty=0;
}
Student::~Student()///包含 指向动态存储空间的指针类型,所以析构函数要自己写啦
{
if(specialty)
delete []specialty;
}
int main()
{
Student zhang("computer");
Date Birthday(1990,10,17);
Birthday.Display(zhang);
return 0;
}
三、友元类
定义:将一个类声明为另一个类的友元。
作用:若一个类被声明为另一个类的友元,则该类中的所有成员函数都是另一个类的友元成员,都可以访问另一个类的所有成员。
例子:将Student类作为Date的友元类,验证Student类中的成员函数可以直接调用Date类中的数据成员
#include<iostream>
#include<cstring>
using namespace std;
class Student; ///向前引用
class Date
{
private:
int year;
int month;
int day;
public:
Date(int ,int ,int);
void Display();
friend Student;
};
class Student
{
private:
char *specialty;///只要看到char指针,不用想,肯定指向动态存储空间
char *name;
public:
Student(char *pn,char *pSpec);
~Student();
void Display(Date &);///Date中有一个Display,Student 类中也有一个Display,虽然名字相同的,但执行的功能却大不相同
};
Date::Date(int y,int m,int d):year(y),month(m),day(d)///另一种赋值方式
{}
void Date::Display()
{
cout<<year<<"-"<<month<<"-"<<day<<endl;
}
Student::Student(char *pn,char *pSpec)
{
if(pSpec)///如果pSpec指向的内容不为空,说明它指向某个空间
{
specialty=new char[strlen(pSpec)+1];///申请与pSpec指向的空间大小相同的 动态存储空间,并返回首地址
strcpy(specialty,pSpec);///将pSpec指向的动态存储空间的内容 赋给 specialty指向的动态存储空间
}
else
specialty=0;
if(pn)
{
name=new char[strlen(pn)+1];
strcpy(name,pn);
}
else name=0;
}
Student::~Student()
{
if(specialty)///指向动态存储空间
delete []specialty;///释放specialty所指的动态存储空间
if(name)
delete []name;
}
void Student::Display(Date &obj)
{
cout<<name<<endl;
cout<<specialty<<endl;
obj.Display();
cout<<"Date's another format is:";
cout<<obj.month<<"-"<<obj.day<<"-"<<obj.year<<endl;///因为Student为Date的友元类,所以Student的成员函数Display中可以直接调用Date中的数据成员
}
int main()
{
Student boy("zhang","computer");
Date birthday(1990,10,17);
boy.Display(birthday);
return 0;
}