一、友元
在类里面有公有成员,私有成员,保护成员。
公有成员:是既可以在类外访问也可以在类里访问
私有成员:需要该类的成员函数才能对私有成员的访问
但如果要通过一个函数去访问私有成员,但这个函数不属于该类里面的函数。
这就是"友元"起到作用**
C++不跟C一样,在C里面定义的数据,没有访问规则,可以直接去访问它,但是在C++这门语言里面定义了各种访问权限规则,什么时候可以去访问这个数据,什么时候又不能去访问这个数据这些都有规定,这样使得数据更安全,不容易被破坏,这就是C++其中的封装特性
而友元呢,破坏了这种数据的隐藏,隐蔽性的特点,数据都是被隐藏在一个安全的地方,而友元就相当于在这个很安全的地方装了一扇窗子,可以通过这扇窗子进去,访问这个数据。
二、友元函数
友元函数示例:
#include <iostream>
using namespace std;
class Point
{
public:
friend Point middle(const Point& a, const Point& b); //声明middle是Point类的友元函数
Point(float a, float b) : x(a), y(b) {}
void printf()
{
cout << "中点坐标:" << x << "," << y << endl;
}
private:
float x;
float y;
};
//通过middle函数可以直接访问private里面的数据
//middle这个函数不属于任何类的成员函数
Point middle(const Point& a, const Point& b)
{
Point c((a.x + b.x) / 2, (a.y + b.y) / 2);
return c;
}
int main(int argc, char* argv[])
{
Point a(1, 5);
Point b(2, 7);
middle(a, b).printf();
return 0;
}
如果想在类外去访问该类的private数据成员,就得声明该类外的函数是该类的友元函数,通过声明后的友元函数才能对该类的私有成员进行访问。
举个现实生活的例子:
友元友元不就是朋友的关系嘛,我想去你家里面玩,陌生人让进嘛?肯定不让进,去你家玩,肯定是朋友的关系,在这里Point这个类就相当于你的家,middle这个函数相当于这个人,还要知道middle这个人到底是朋友呢还是陌生人呢,就取决于他是否声明的友元,声明了就是朋友,没有声明就是陌生人。
三、一个类的成员函数是另外一个类的友元
#include <iostream>
#include <cstring>
#pragma warning(disable : 4996 26432 26401 26409 26440 26485 4150)
using namespace std;
class Person;
class Spouse
{
public:
Spouse(const Person& Phu, const Person& Pw);
~Spouse() { delete Phusband; delete Pwife; }
void Show() const;
private:
Person* Phusband;
Person* Pwife;
};
class Person
{
public:
friend void Spouse::Show() const; //声明Spouse类中的Show成员函数是Persou类的友元函数
Person(const char* nm, int ag, const char* sx) : age(ag) {
strcpy(name, nm);
strcpy(sex, sx);
}
void Show()
{
cout << name << " " << age << " " << sex << endl;
}
private:
char name[10];
int age;
char sex[10];
};
Spouse::Spouse(const Person& Phu, const Person& Pw)
{
Phusband = new Person(Phu);
Pwife = new Person(Pw);
}
void Spouse::Show() const
{
cout << "丈夫:" << Phusband->name << " " << Phusband->age << " " << Phusband->sex << endl;
cout << "妻子:" << Pwife->name << " " << Pwife->age << " " << Pwife->sex << endl;
}
int main()
{
Person hus("胡强", 33, "男");
Person wf("小风", 32, "女");
Spouse sp(hus, wf);
hus.Show();
wf.Show();
sp.Show();
system("pause");
return 0;
}
定义了两个类Spouse和Persou
在类Spouse前面引用了class Person,因为类Spouse需要用到类Person,而Person在Spouse的后面
为了解决这个问题,所以在类Spouse前面引用类Serson.
但注意的是:类提前声明使用的范围是有限的,只有正式声明一个类才能去定义这个类的对象,在类Spouse中数据成员不能直接定义为Persou类的对象
改为:
Persou Phusband;
Persou Pwife;
就会报错,这是因为正式声明一个类之前,编译器无法确定Persou类需要多大的内存空间,所以对一个类做了提前引用声明后,可以用该类的名字去指向该类的指针变量或对象的引用。因为指针变量和引用本身的大小是固定的。
这个代码是将Spouse类的成员函数show()
作为Persou的友元函数,那么可以通过Spouse类中的show()去访问Persou中的数据成员
四、友元类
#include <iostream>
#include <cstring>
#pragma warning(disable : 26440 26485 26496 4996 4150 26432 26401 26409)
using namespace std;
class Person;
class Spouse
{
private:
Person* pHusband;
Person* pWife;
public:
Spouse(const Person& hus, const Person& wf);
~Spouse() { delete pHusband; delete pWife; }
void Show() const;
};
class Person
{
private:
char name[10];
int age;
char sex[10];
public:
friend class Spouse; //声明Phusband是Pwife友元类
Person(const char* nm, const int ag, const char* se) : age(ag)
{
strcpy_s(name, nm);
strcpy_s(sex, se);
}
void Show() const
{
cout << name << " " << age << " " << sex << endl;
}
};
Spouse::Spouse(const Person& hus, const Person& wf)
{
pHusband = new Person(hus);
pWife = new Person(wf);
}
void Spouse::Show() const
{
cout << "丈夫: " << pHusband->name << " " << pHusband->age << " " << pHusband->sex << endl;
cout << "妻子: " << pWife->name << " " << pWife->age << " " << pWife->sex << endl;
}
int main()
{
Person huf("张强", 18, "男");
Person wf("小丽", 17, "女");
Spouse sp(huf, wf);
huf.Show();
wf.Show();
sp.Show();
system("pause");
return 0;
}
如果把以上代码改为:
#include <iostream>
#include <cstring>
#pragma warning(disable : 26440 26485 26496 4996 4150 26432 26401 26409)
using namespace std;
class Spouse;
class Person
{
private:
char name[10];
int age;
char sex[10];
public:
friend class Spouse; //声明Phusband是Pwife友元类
Person(const char* nm, const int ag, const char* se) : age(ag)
{
strcpy_s(name, nm);
strcpy_s(sex, se);
}
void Show() const
{
cout << name << " " << age << " " << sex << endl;
}
};
class Spouse
{
private:
Person pHusband;
Person pWife;
public:
Spouse(const Person& hus, const Person& wf) : pHusband(hus), pWife(wf) {}
void Show() const;
};
void Spouse::Show() const
{
cout << "丈夫: " << pHusband.name << " " << pHusband.age << " " << pHusband.sex << endl;
cout << "妻子: " << pWife.name << " " << pWife.age << " " << pWife.sex << endl;
}
int main()
{
Person huf("张强", 18, "男");
Person wf("小丽", 17, "女");
Spouse sp(huf, wf);
huf.Show();
wf.Show();
sp.Show();
system("pause");
return 0;
}
让Person类在Spouse类的前面 那么在Spouse类中可以直接定义对象
Person pHusband;
Person pWife;
先声明Person类,才能知道Person这个类的大小,才能在Spouse类中定义Person类的对象,编译器才能知道具体要分配多大的内存空间
如果将friend class Spouse改为:
friend void Spouse:: Show() const;
编译器会报错,由于先定义的是Person类,后定义的是Spouse类,如果在先声明的Person类中定义一个Spouse类中的Show函数是Person的友元, 编译器找不到Spouse类中是否存在Show这样的一个函数。