IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 友元(C++) -> 正文阅读

[C++知识库]友元(C++)





友元

视频链接



友元的使用时机

在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术



友元的目的就是让一个函数或者类 访问另一个类中私有成员

友元的关键字为 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() {
		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也是GoodGay的成员
	Building building;
};

void GoodGay::visit() {

	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;
}





细小改动:把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();// 让visit函数可以访问Building中私有成员
	void visit2();//这只是一个普通的成员函数,无法访问Building中私有成员
};
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;
	 //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和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.类中的成员函数不能再类外声明,只能在类内声明

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 10:54:41  更:2022-09-13 10:58:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 12:20:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码