友元
目的:访问类中的私有属性
- 类的主要特点之一是数据隐藏,即类的私有成员无法在类的外部(作用域之外)访问。但是,有时候需要在类的外部访问类的私有成员,怎么办?
- 解决方法是使用友元函数,友元函数是一种特权函数,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;
//1.全局函数做友元函数
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;//不可访问
cout << "好基友正在访问" << building->m_BedRoom << endl;//做成友元之后可以访问
}
void test01()
{
Building* building = new Building;//new完了就会调用Building的构造函数,就会开辟内存给building指向,该内存里有"客厅" 和 "卧室"
goodGay(building);
}
int main()
{
test01();
system("pause");
return 0;
}
友元练习
请编写电视机类,电视机有开机和关机状态,有音量,有频道,提供音量操作的方法,频道操作的方法。由于电视机只能逐一调整频道,不能指定频道,增加遥控类,遥控类除了拥有电视机已有的功能,再增加根据输入调台功能。
点击查看代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
class Television
{
//friend class Remote;
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(); //增加音量+1
television.VolumeUp(); //增加音量+1
television.VolumeUp(); //增加音量+1
television.VolumeUp(); //增加音量+1
television.ChannelUp(); //频道+1
television.ChannelUp(); //频道+1
television.ShowTeleState();
}
//通过遥控操作电视
void test02(){
//创建电视
Television television;
//创建遥控
Remote remote(&television);
remote.OnOrOff();
remote.ChannelUp();//频道+1
remote.ChannelUp();//频道+1
remote.ChannelUp();//频道+1
remote.VolumeUp();//音量+1
remote.VolumeUp();//音量+1
remote.VolumeUp();//音量+1
remote.VolumeUp();//音量+1
remote.ShowTeleState();
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
友元强化
1.先声明,在MyArray.h的头文件中
点击查看代码
#pragma once
#include<iostream>
using namespace std;
class MyArray
{
public:
MyArray();//默认构造 100的容量
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);//new 的方式指定拷贝构造
MyArray array3 = *array2;//构造函数返回的本体
MyArray* array4 = array;//这个是声明一个指针 和array执行的地址相同,所以不会调用拷贝构造。
//delete 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;//error,返回值是int,这句代码相当于写了一句:10000 = 100
cout << array3.getData(0) << endl;
cout << array3[0] << endl;
delete array;
}
int main()
{
test01();
system("pause");
return 0;
}