一、类的友元
生活中你的家有客厅(public),有你的卧室(private),客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去,但是,你也可以允许你的好闺蜜好基友进去
-
友元关系:一个类主动声明哪些其他函数或者类是它的朋友,进而给它们提供对本类的访问特许
- 一些类中的私有属性想让类外的一些特殊的函数或者其他类进行访问
-
一种数据共享机制
- 不同类或对象的成员函数之间
- 类的成员函数与一般函数之间
-
友元是C++提供的一种破坏数据封装和数据隐藏的机制,为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元
二、友元函数
- 在类中用关键字friend修饰的非成员函数
- 友元函数不是类的内部成员函数,而是一个类外的函数
- 在友元函数体内可以通过对像名访问类中的private和protected成员
- 在类中声明友元函数原型,在类外定义该友元函数
- 作用:
- 增加灵活性,可以在封装和快速性方面做合理选择
示例:
-
建筑物类中,客厅是公有成员,可在类外进行访问,卧室是私有成员,在类外不可访问到
-
在test01中调用建筑物类,访问卧室会报错
-
完整程序:存在错误,类外无法访问私有成员
// 建筑物类
class Building {
public:
// 构造函数
Building() {
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
public:
string m_SittingRoom; // 客厅,公共属性
private:
string m_BedRoom; // 卧室,私有属性
};
// 全局函数
// 要求能够访问Building类中的公共和私有成员
void goodGay(Building *building) {
cout << "好基友全局函数 正在访问:" << building->m_SittingRoom << endl; // 公共属性
cout << "好基友全局函数 正在访问:" << building->m_BedRoom << endl; // 私有属性
}
void test01() {
Building building;
goodGay(&building);
}
int main() {
test01();
}
- 解决方法:定义友元
# include <iostream>
# include <string>
using namespace std;
// 建筑物类
class Building {
friend void goodGay(Building* building);
public:
// 构造函数
Building() {
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
public:
string m_SittingRoom; // 客厅
private:
string m_BedRoom; // 卧室
};
// 全局函数
// 要求能够访问Building类中的公共和私有成员
void goodGay(Building *building) {
cout << "好基友全局函数 正在访问:" << building->m_SittingRoom << endl;
cout << "好基友全局函数 正在访问:" << building->m_BedRoom << endl;
}
void test01() {
Building building;
goodGay(&building);
}
int main() {
test01();
}
示例:计算两个点之间的距离
#include <iostream>
#include <cmath>
class Point {
private:
int x, y;
public:
Point(int x = 0, int y = 0) {
this->x = x;
this->y = y;
}
int getX(){ return x; }
int getY(){ return y; }
friend double dist(Point &a, Point &b); // 类内声明友元函数原型
}
// 类外定义友元函数dist()
// 传入两个Point类对象
double dist(Point& a, Point& b) {
double x = a.x - b.x;
double y = a.y - b.y;
return (sqrt(x*x + y*y));
}
int main(){
Point p1(1, 1), p2(4, 5);
cout << "The distance is: ";
cout << dist(p1, p2) << endl;
return 0;
}
/************* 不用友元 ***********/
class Point {
private:
int x, y;
public:
Point(int x = 0, int y = 0) {
this->x = x;
this->y = y;
}
int getX(){ return x; }
int getY(){ return y; }
}
double dist(Point& a, Point& b) {
double x = a.getX() - b.getX(); // 类Point提供了getX()函数才可以这样
double y = a.getY() - b.getY();
return (sqrt(x*x + y*y));
}
三、友元类
- 一个类可以将另一个类声明为友元类
- 若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员
- 注意:
- 友元关系不能传递
- 友元关系是单向的
- 友元关系不被继承
示例:
- 将一个类定义为另一个类的友元
将GoodGay类定义为Building类的友元,使GoodGay类可以访问Building类的私有成员
# include <iostream>
# include <string>
using namespace std;
class Building; // 类声明
class GoodGay {
public:
// 构造函数
GoodGay();
void visit(); // 参观函数,访问Building中的属性
Building* building;
};
class Building {
// GoodGay类是本类中的好朋友,可以访问本类中的私有成员
friend class GoodGay;
public:
// 构造函数
Building();
public:
string m_SittingRoom; // 客厅
private:
string m_BedRoom; // 卧室
};
//类外写成员函数(构造函数)
Building::Building() {
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodGay::GoodGay() {
//创建建筑物对象
building = new Building;
}
// 参观函数,访问Building中的属性
void GoodGay::visit() {
cout << "好基友全局函数 正在访问:" << building->m_SittingRoom << endl;
cout << "好基友全局函数 正在访问:" << building->m_BedRoom << endl;
}
void test01() {
GoodGay gg;
gg.visit();
}
int main() {
test01();
}
- 将一个类的成员函数定义为另一个类的友元
GoodGay类中的visit函数定义为Building类的友元,使visit可以访问Building类的私有成员
GoodGay类中的visit2()函数不可访问Building类的私有成员
# include <iostream>
# include <string>
using namespace std;
class Building; // 类声明
class GoodGay {
public:
// 构造函数
GoodGay();
void visit(); // 让visit函数可以访问Building中的私有成员
void visit2(); // 让visit2函数不可以访问Building中的私有成员
Building* building;
};
class Building {
// 让GoodGay类的成员visit函数可以访问Building中的私有成员
friend void GoodGay::visit();
public:
// 构造函数
Building();
public:
string m_SittingRoom; // 客厅
private:
string m_BedRoom; // 卧室
};
//类外写成员函数(构造函数)
Building::Building() {
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodGay::GoodGay() {
//创建建筑物对象
building = new Building;
}
// 参观函数,访问Building中的属性
void GoodGay::visit() {
cout << "好基友全局函数 正在访问:" << building->m_SittingRoom << endl;
cout << "好基友全局函数 正在访问:" << building->m_BedRoom << endl;
}
void GoodGay::visit2() {
cout << "好基友全局函数 正在访问:" << building->m_SittingRoom << endl;
}
void test01() {
GoodGay gg;
gg.visit();
gg.visit2();
}
int main() {
test01();
}
“好基友全局函数 正在访问:” << building->m_SittingRoom << endl;
}
void test01() {
GoodGay gg;
gg.visit();
gg.visit2();
}
int main() {
test01();
}
[外链图片转存中...(img-g1qKWnVt-1683771873281)]
[外链图片转存中...(img-emG2SPlL-1683771873282)]