首页 > 其他分享 >第七章 类 Part4 友元

第七章 类 Part4 友元

时间:2023-02-16 22:22:41浏览次数:30  
标签:友元 函数 int void MyArray pAddress Part4 第七章

友元

目的:访问类中的私有属性

  • 类的主要特点之一是数据隐藏,即类的私有成员无法在类的外部(作用域之外)访问。但是,有时候需要在类的外部访问类的私有成员,怎么办?
  • 解决方法是使用友元函数,友元函数是一种特权函数,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;
}

image

友元练习

请编写电视机类,电视机有开机和关机状态,有音量,有频道,提供音量操作的方法,频道操作的方法。由于电视机只能逐一调整频道,不能指定频道,增加遥控类,遥控类除了拥有电视机已有的功能,再增加根据输入调台功能。

点击查看代码
#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;
}

标签:友元,函数,int,void,MyArray,pAddress,Part4,第七章
From: https://www.cnblogs.com/Epiephany/p/17128520.html

相关文章

  • 第七章 类和对象 Part3 类的静态成员
    静态成员在类定义中,它的成员(包括成员变量和成员函数),这些成员可以用关键字static声明为静态的,称为静态成员。不管这个类创建了多少个对象,静态成员只有一个拷贝,这个拷贝被......
  • 重学Java-第七章 Java表达式、语句和块
    7.1表达式7.1.1定义 表达式是由数字、运算符、数字分组符号(括号)、自由变量和约束变量等以能求得数值的有意义排列方法所得的组合,约束变量是在表达式中已被指定数值,......
  • 第七章 类Part2
    深拷贝和浅拷贝浅拷贝同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况被称为浅拷贝.一般情况下,浅拷贝没有任何副作用......
  • 第七章 类_Part1
    1.类和对象1.1类和对象的基本概念1.1.1C和C++中struct区别c语言struct只有变量c++语言struct既有变量,也有函数1.1.2类的封装​ 我们编写程序的目的是为了解决现......
  • 实战:第七章:微信H5支付时用户有微信分身停留5秒后未选择哪个微信分身,也未支付就被动回
    三种问题:微信H5支付时用户有微信分身停留5秒后未选择哪个微信分身,也未支付就被动回调到商户支付是否完成的页面安卓H5支付设置了redirect_url后调起微信收银台5秒后回退......
  • 友元
    友元如果要访问类的私有成员变量,调用类的公有成员函数是唯一的办法,而类的私有成员函数则无法访问。友元提供了另一访问类的私有成员的方案。友元有三种:l友元全局函数。......
  • 《程序是怎样跑起来的》·第七章 程序是在何种环境下运行
    开篇(1)应用的运行环境,指的是什么?   操作系统和计算机本身(硬件)的种类(2)Macintosh用的操作系统(MacOS),在AT兼容机上能运行吗?   无法运行(3)Windows上的应用,在MacOS......
  • 【C++复习】第七章 类的继承(基类、派生类、虚基类)
    1、基类与派生类类的继承:面向对象的程序设计中提供了类的继承机制,允许程序员在保持原有类特性的基础上,进行更具体、更详细的定义 用途:代码的重用性(继承)和可扩充性(派生)......
  • Linux基础课:第七章笔记--管道,环境变量与常用变量
    开始第七章的学习。技术都是手段,目标是最短的时间内,将学到的知识转化成想要的东西。y总金句:如果想在35岁之前出人头地,能正常工作的不过十来年,那么现在就应该好好学习,工作......
  • 代码随想录算法训练营第二十四天 | 第七章 回溯算法-理论基础,77. 组合
    一、参考资料理论基础题目链接/文章讲解:https://programmercarl.com/%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html视频讲解:htt......