友元
视频链接
友元的使用时机
在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术
友元的目的就是让一个函数或者类 访问另一个类中私有成员
友元的关键字为 friend
友元的三种实现
1. 全局函数做友元
#include<iostream>
using namespace std;
#include<string>
//建筑物类
class Building {
public:
// 注意友元函数声明的位置
// 在类中最前面写全局函数的声明
//注意函数实现的时候不要更改参数列表(也就是不要发生重载)
friend void test01(Building *building);
string m_sittingRoom;// 客厅
Building() {
m_sittingRoom = "客厅";
m_BedRoom = "卧室";
}
private:
string m_BedRoom;// 卧室
};
// 全局函数的实现
// 下面的函数传递方式是地址传递(形参是个指针)
void test01(Building* building) {
cout << "好基友的全局函数 正在访问:" <<building->m_sittingRoom<<endl;
cout << "好基友的全局函数 正在访问:" << building->m_BedRoom << endl;
}
// 也可以是引用传递
// 不过在类中最上面的声明得改成:friend void test01(Building &building);
/*void test01(Building& building) {
cout << "好基友的全局函数 正在访问:" << building.m_sittingRoom << endl;
cout << "好基友的全局函数 正在访问:" << building.m_BedRoom << endl;
}*/
void test02() {
Building m_building;
test01(&m_building);
}
int main() {
test02();
system("pause");
return 0;
}
全局函数做友元,只需把全局函数的声明写到类的最上面,然后在前面加个关键字friend就行。 比如: class Building { public: friend void test01(Building *building); … };
2. 类做友元
#include<iostream>
using namespace std;
#include<string>
class GoodGay;
class Building {
public:
friend GoodGay;
Building();
string m_SittingRoom;
private:
string m_Production;
};
Building::Building() {
m_SittingRoom = "卢浮宫";
m_Production = "蒙娜丽莎";
}
class GoodGay {
public:
void visit();
Building building;
};
void GoodGay::visit() {
cout << "好基友的类 正在访问:" << building.m_SittingRoom << endl;
cout << "好基友的类 正在观看:" << building.m_Production << endl << endl;;
building.m_SittingRoom = "故宫";
building.m_Production = "清明上河图";
cout << "过了一段时间后,好基友的类正在访问:" << building.m_SittingRoom << endl;
cout << "此时他正在观看:" << building.m_Production<< endl<<endl;
}
void test01() {
Building b;
GoodGay gg;
gg.visit();
}
int main() {
test01();
system("pause");
return 0;
}
细小改动:把GoodGay类中的Building building;这句话加到visit()函数中,也可以成功运行
#include<iostream>
using namespace std;
#include<string>
// 要想提前引用未初始化的类的话必须得写一个类的声明,就像函数声明一样
// 告诉一下编译器这个函数的存在,之不过我一会再写。 不让编译器报错
class GoodGay;
class Building {
public:
// 类做友元
friend GoodGay;
// 一般在类内构造函数,但其实可以在类外构造函数
/*Building() {
m_SittingRoom = "卢浮宫";
m_Production = "蒙娜丽莎";
}*/
Building();
string m_SittingRoom;//参观地
private:
string m_Production;//作品
};
//在类外写成员函数
// 要加作用域,证明他是Building类和GoodGay类中的
// 注意区分构造函数和其他函数的写法,有返回值的返回值写在最前面
Building::Building() {
m_SittingRoom = "卢浮宫";
m_Production = "蒙娜丽莎";
}
// 友元类用来访问其他类中的私有成员属性
class GoodGay {
public:
void visit();//参观函数,访问Buidling中的所有属性
// 友元类不可能直接访问Building中的成员,它是间接访问的
// 所以在友元类中创建Building类对象building(building是个值不是指针),通过他去访问Building类中的成员
};
void GoodGay::visit() {
// 在成员函数中创建建筑类对象
Building building;
cout << "好基友的类 正在访问:" << building.m_SittingRoom << endl;
cout << "好基友的类 正在观看:" << building.m_Production << endl << endl;;
building.m_SittingRoom = "故宫";
building.m_Production = "清明上河图";//虽然m_Production是私有属性,但友元类仍然可以间接访问并修改它的值
cout << "过了一段时间后,好基友的类正在访问:" << building.m_SittingRoom << endl;
cout << "此时他正在观看:" << building.m_Production<< endl<<endl;
}
void test01() {
Building b;
// 友元类访问的对象是Building中的私有成员变量。
//注意既然我们要打印出Builiding中成员的值,那么Building一定要示例化(并给里面的成员赋值),不然我们怎么知道Building里面的成员属性是什么呢。
// 我们可以在友元类中就把Building实例化出来或者在全局函数中实例化出来。反正一定得给Builiding里的成员变量附上值。
// 如果Building不实例化Builiding里的成员变量没有值。那么我们通过友元类去打印Building里面的属性就没意义了。
GoodGay gg;
// 打印函数肯定得写在Building实例化之后,无论Building在全局函数里实例化还是在友元类中被实例化出对象
// 现有值,再打印
gg.visit();
}
int main() {
test01();
system("pause");
return 0;
}
1.友元类不能直接访问被访问类中的成员变量,它是间接访问的。 所以在友元类中不要忘了创建被访问类的对象。
2.先赋值再打印
提升:通过指针访问类中成员
#include<iostream>
using namespace std;
#include<string>
class goodGay;
class Building
{
//告诉编译器 goodGay类是Building类的好朋友,可以访问到Building类中私有内容
friend class goodGay;
public:
Building();
public:
string m_SittingRoom;
private:
string m_BedRoom;
};
Building::Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}
class goodGay
{
public:
goodGay();
void visit();
private:
// 创建建筑类对象building,通过*building(指针)去访问Building类中的成员
Building* building;
};
goodGay::goodGay()
{
// 在友元类中就把Building构造出来了
// Building里的成员变量也附上值了
//在堆区开辟数据,返回的是Building这个数据类型的指针
// 而且这个指针指向的是个类
// builiding是类的地址,*building值的才是实例化的类
// building->m_SittringRoom=(*building).m_SittingRoom
building = new Building;//这一句话在创建建筑类的同时也执行了Building类的构造函数
}
void goodGay::visit()
{
cout << "(*building.方式访问)好基友的类 正在:" << (*building).m_SittingRoom << endl;
cout << "(building->方式访问)好基友的类 正在:" << building->m_SittingRoom << endl << endl;
cout << "(*building.方式访问)一段时间后好基友的类 正在:" << (*building).m_BedRoom << endl;
cout << "(building->方式访问)一段时间后好基友的类 正在:" << building->m_BedRoom << endl << endl;
(*building).m_SittingRoom = "打游戏";
building->m_BedRoom = "睡着";//哪怕 m_BedRoom是私有成员属性,友元类也能更改
cout << "(*building.方式访问)再过了一段时间后好基友的类 正在:" << (*building).m_SittingRoom << endl;
cout << "(building->方式访问)再过了一段时间后好基友的类 正在:" << building->m_SittingRoom << endl << endl;
cout << "(*building.方式访问)终于好基友的类 已经:" << (*building).m_BedRoom << "了"<<endl;
cout << "(building->方式访问)终于好基友的类 已经:" << building->m_BedRoom << "了"<<endl << endl;
}
void test01()
{
goodGay gg;
gg.visit();
}
int main() {
test01();
system("pause");
return 0;
}
1.类中的函数其实都可以在类内声明类外初始化,不过一定要写明作用域,不然怎么知道它是哪个类的
2.注意类指针如何访问类中的属性 如:Building *building; 访问属性a,可以这么写:building->a 也可以这么写:(*building).a
3.友元类不能直接访问被访问类中的成员变量,它是间接访问的。 所以在友元类中不要忘了创建被访问类的对象。
4.先赋值再打印
5.跟函数一样,要想提前使用未初始化的类,记得加个声明,告诉编译器。
3. 成员函数做友元
#include<iostream>
using namespace std;
#include<string>
class Building;
class GoodGay {
public:
GoodGay();
Building* building;
void visit();
void visit2();
};
class Building {
public:
friend void GoodGay::visit();
Building();
string m_Name;
private:
string m_Production;
};
GoodGay::GoodGay() {
building = new Building;
}
void GoodGay::visit() {
cout << "(*building.表示)好基友的类1 正在访问:" << (*building).m_Name << endl;
cout << "(building->表示)好基友的类1 正在看:" << building->m_Production << endl<<endl;
building->m_Name = "故宫";
(*building).m_Production = "清明上河图";
cout << "(*building.表示)过了一段时间后好基友的类 正在访问:" << (*building).m_Production << endl;
cout << "(building->表示)过了一段时间后好基友的类 正在观看:" << building->m_Production << endl << endl;
}
void GoodGay::visit2() {
cout << "好基友的类2 正在访问:" << building->m_Name << endl;
}
Building::Building() {
m_Name = "卢浮宫";
m_Production = "蒙娜丽莎";
}
void test01() {
GoodGay gg;
gg.visit();
gg.visit2();
}
int main() {
test01();
system("pause");
return 0;
}
注意类GoodGay和Building类的顺序不能更换位置
不能写成下面这样
#include<iostream>
using namespace std;
#include<string>
class GoodGay;
// void GoodGay::visit();成员函数不能在类外声明!!!
class Building {
public:
friend void GoodGay::visit();//写清到底是哪个类下的成员函数!!!
Building();
string m_Name;
private:
string m_Production;
};
class GoodGay {
public:
GoodGay();
Building* building;
void visit();// 让visit函数可以访问Building中私有成员
void visit2();//这只是一个普通的成员函数,无法访问Building中私有成员
};
GoodGay::GoodGay() {
// 通过指针创建建筑类对象并实例化
building = new Building;
}
void GoodGay::visit() {
cout << "(*building.表示)好基友的类1 正在访问:" << (*building).m_Name << endl;
cout << "(building->表示)好基友的类1 正在看:" << building->m_Production << endl<<endl;//可以访问
building->m_Name = "故宫";
(*building).m_Production = "清明上河图";
cout << "(*building.表示)过了一段时间后好基友的类 正在访问:" << (*building).m_Production << endl;
cout << "(building->表示)过了一段时间后好基友的类 正在观看:" << building->m_Production << endl << endl;
}
void GoodGay::visit2() {
cout << "好基友的类2 正在访问:" << building->m_Name << endl;
//cout << "好基友的类2 正在看:" << building->m_Production << endl;//报错访问不到
}
Building::Building() {
m_Name = "卢浮宫";
m_Production = "蒙娜丽莎";
}
void test01() {
GoodGay gg;
gg.visit();
gg.visit2();
}
int main() {
test01();
system("pause");
return 0;
}
原因如下:上面那样子会导致GoodGay在没定义前被使用。
1.成员函数做友元,一定要写清作用域,说明是哪个类下的成员函数 2.好基友的类一般要写在被访问的类的前面!!!先写好基友类再写要访问的类。 3.类中的成员函数不能再类外声明,只能在类内声明
|