友元
目的:访问类中的私有属性
- 类的主要特点之一是数据隐藏,即类的私有成员无法在类的外部(作用域之外)访问。但是,有时候需要在类的外部访问类的私有成员,怎么办?
- 解决方法是使用友元函数,友元函数是一种特权函数,c++允许这个特权函数访问私有成员。这一点从现实生活中也可以很好的理解:
比如你的家,有客厅,有你的卧室,那么你的客厅是Public的,所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去,但是呢,你也可以允许你的闺蜜好基友进去。
- 程序员可以把一个全局函数、某个类中的成员函数、甚至整个类声明为友元。
友元语法
- friend关键字只出现在声明处
- 其他类、类成员函数、全局函数都可声明为友元
- 友元函数不是类的成员,不带this指针
- 友元函数可访问对象任意成员属性,包括私有属性,其目的就是访问类中私有的属性
友元类注意
- 友元关系不能被继承。
- 友元关系是单向的,类A是类B的朋友,但类B不一定是类A的朋友。
- 友元关系不具有传递性。类B是类A的朋友,类C是类B的朋友,但类C不一定是类A的朋友。
- 全局函数做友元函数,就是把全局函数写到类中做声明,并且加上friend关键字
思考: c++是纯面向对象的吗?
| 如果一个类被声明为friend,意味着它不是这个类的成员函数,却可以修改这个类的私有成员,而且必须列在类的定义中,因此他是一个特权函数。c++不是完全的面向对象语言,而只是一个混合产品。增加friend关键字只是用来解决一些实际问题,这也说明这种语言是不纯的。毕竟c++设计的目的是为了实用性,而不是追求理想的抽象。 |
| --- Thinking in C++ |
点击查看代码
| #define _CRT_SECURE_NO_WARNINGS |
| #include<iostream> |
| #include<string> |
| using namespace std; |
| |
| |
| |
| void goodGay(); |
| class Building |
| { |
| |
| |
| friend void goodGay(Building* building); |
| public: |
| Building() |
| { |
| this->m_SittingRoom = "客厅"; |
| this->m_BedRoom = "卧室"; |
| } |
| |
| |
| public: |
| string m_SittingRoom; |
| private: |
| string m_BedRoom; |
| |
| }; |
| |
| |
| void goodGay(Building * building) |
| { |
| cout << "好基友正在访问" << building->m_SittingRoom << endl; |
| |
| cout << "好基友正在访问" << building->m_BedRoom << endl; |
| |
| } |
| |
| |
| void test01() |
| { |
| Building* building = new Building; |
| goodGay(building); |
| } |
| |
| |
| int main() |
| { |
| test01(); |
| |
| system("pause"); |
| return 0; |
| } |

友元练习
请编写电视机类,电视机有开机和关机状态,有音量,有频道,提供音量操作的方法,频道操作的方法。由于电视机只能逐一调整频道,不能指定频道,增加遥控类,遥控类除了拥有电视机已有的功能,再增加根据输入调台功能。
点击查看代码
| #define _CRT_SECURE_NO_WARNINGS |
| #include<iostream> |
| #include<string> |
| using namespace std; |
| |
| class Television |
| { |
| |
| public: |
| enum{On,Off}; |
| enum{minVol,maxVol = 100}; |
| enum{minChannel = 1,maxChannel = 255}; |
| public: |
| Television() |
| { |
| mState = Off; |
| mVolume = minVol; |
| mChannel = minChannel; |
| } |
| |
| void OnOrOff() |
| { |
| this->mState = (this->mState == On ? Off : On); |
| } |
| |
| void VolumeUp() |
| { |
| if (this->mVolume >= maxVol) |
| { |
| return; |
| } |
| this->mVolume++; |
| } |
| |
| void VolumeDown() |
| { |
| if (this->mVolume <= minVol) |
| { |
| return; |
| } |
| this->mVolume--; |
| } |
| |
| void ChannelUp() |
| { |
| if (this->mChannel >= maxChannel) |
| { |
| return; |
| } |
| this->mChannel++; |
| } |
| |
| void ChannelDown() |
| { |
| if (this->mChannel <= minChannel) |
| { |
| return; |
| } |
| this->mChannel--; |
| } |
| |
| void ShowTeleState() |
| { |
| cout << "开机状态:" << (mState == On ? "已开机" : "已关机") << endl; |
| if (mState == On) |
| { |
| cout << "当前音量:" << mVolume << endl; |
| cout << "当前频道:" << mChannel<< endl; |
| } |
| cout << "----------------------" << endl; |
| } |
| |
| private: |
| int mState; |
| int mVolume; |
| int mChannel; |
| }; |
| |
| |
| |
| class Remote{ |
| public: |
| Remote(Television* television){ |
| pTelevision = television; |
| } |
| public: |
| void OnOrOff(){ |
| pTelevision->OnOrOff(); |
| } |
| |
| void VolumeUp(){ |
| pTelevision->VolumeUp(); |
| } |
| |
| void VolumeDown(){ |
| pTelevision->VolumeDown(); |
| } |
| |
| void ChannelUp(){ |
| pTelevision->ChannelUp(); |
| } |
| void ChannelDown(){ |
| pTelevision->ChannelDown(); |
| } |
| |
| void SetChannel(int channel){ |
| if (channel < Television::minChannel || channel > Television::maxChannel){ |
| return; |
| } |
| pTelevision->mChannel = channel; |
| } |
| |
| |
| void ShowTeleState(){ |
| pTelevision->ShowTeleState(); |
| } |
| private: |
| Television* pTelevision; |
| }; |
| |
| |
| |
| void test01(){ |
| |
| Television television; |
| television.ShowTeleState(); |
| television.OnOrOff(); |
| television.VolumeUp(); |
| television.VolumeUp(); |
| television.VolumeUp(); |
| television.VolumeUp(); |
| television.ChannelUp(); |
| television.ChannelUp(); |
| television.ShowTeleState(); |
| } |
| |
| |
| |
| void test02(){ |
| |
| Television television; |
| |
| Remote remote(&television); |
| remote.OnOrOff(); |
| remote.ChannelUp(); |
| remote.ChannelUp(); |
| remote.ChannelUp(); |
| remote.VolumeUp(); |
| remote.VolumeUp(); |
| remote.VolumeUp(); |
| remote.VolumeUp(); |
| remote.ShowTeleState(); |
| } |
| |
| int main() |
| { |
| test01(); |
| test02(); |
| |
| system("pause"); |
| return 0; |
| } |
| |
友元强化
1.先声明,在MyArray.h的头文件中
点击查看代码
| #pragma once |
| #include<iostream> |
| using namespace std; |
| |
| class MyArray |
| { |
| public: |
| MyArray(); |
| MyArray(int capacity); |
| MyArray(const MyArray& array); |
| |
| ~MyArray(); |
| |
| |
| void push_Back(int val); |
| |
| |
| int getData(int index); |
| |
| |
| void setData(int index,int val); |
| |
| |
| int getSize(); |
| |
| |
| int getCapacity(); |
| |
| |
| int & operator[](int index); |
| |
| |
| private: |
| int* pAddress; |
| int m_Size; |
| int m_Capacity; |
| |
| }; |
2.实现MyArrary.cpp
点击查看代码
| #include "MyArray.h" |
| #include<iostream> |
| using namespace std; |
| |
| |
| MyArray::MyArray() |
| { |
| this->m_Capacity = 100; |
| this->m_Size = 0; |
| this->pAddress = new int[this->m_Capacity]; |
| } |
| |
| |
| MyArray::MyArray(int capacity) |
| { |
| cout << "有参函数被调用" << endl; |
| this->m_Capacity = capacity; |
| this->m_Size = 0; |
| this->pAddress = new int[this->m_Capacity]; |
| } |
| |
| |
| MyArray::MyArray(const MyArray& array) |
| { |
| cout << "拷贝构造被调用" << endl; |
| this->pAddress = new int[array.m_Capacity]; |
| this->m_Size = array.m_Size; |
| this->m_Capacity = array.m_Capacity; |
| |
| for (int i = 0; i < array.m_Size; i++) |
| { |
| this->pAddress[i] = array.pAddress[i]; |
| } |
| } |
| |
| |
| MyArray::~MyArray() |
| { |
| if (this->pAddress != NULL) |
| { |
| cout << "析构函数被调用~" << endl; |
| delete[] this->pAddress; |
| this->pAddress = NULL; |
| } |
| } |
| |
| |
| void MyArray::push_Back(int val) |
| { |
| |
| this->pAddress[this->m_Size] = val; |
| this->m_Size++; |
| } |
| |
| int MyArray::getData(int index) |
| { |
| return this->pAddress[index]; |
| } |
| |
| |
| void MyArray::setData(int index, int val) |
| { |
| this->pAddress[index] = val; |
| } |
| |
| |
| int MyArray::getSize() |
| { |
| return this->m_Size; |
| } |
| |
| |
| int MyArray::getCapacity() |
| { |
| return this->m_Capacity; |
| } |
| |
| |
| int & MyArray::operator[](int index) |
| { |
| |
| return this->pAddress[index]; |
| } |
3.最后测试,在测试文件中
点击查看代码
| #include "MyArray.h" |
| #include<iostream> |
| using namespace std; |
| |
| void test01() |
| { |
| |
| MyArray* array = new MyArray(30); |
| |
| |
| MyArray* array2 = new MyArray(*array); |
| MyArray array3 = *array2; |
| |
| MyArray* array4 = array; |
| |
| |
| for (int i = 0; i < 10; i++) |
| { |
| array2->push_Back(i); |
| } |
| |
| |
| for (int i = 0; i < 10; i++) |
| { |
| cout << array2->getData(i) << endl; |
| } |
| |
| |
| array2->setData(0, 100); |
| |
| |
| cout << array2->getData(0) << endl; |
| |
| |
| cout << array2->getCapacity() << endl; |
| |
| |
| cout << array2->getSize() << endl; |
| |
| |
| array3.push_Back(10000); |
| cout << array3.getData(0) << endl; |
| cout << array3[0] << endl; |
| array3[0] = 100; |
| cout << array3.getData(0) << endl; |
| cout << array3[0] << endl; |
| |
| delete array; |
| } |
| |
| int main() |
| { |
| test01(); |
| |
| system("pause"); |
| return 0; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具