C++友元

C++友元类之间的注意点及其主要用法

本次感悟是在C++primer第五版251、252练习的时候得到的,具体的案例大家可以自己查看!
首先友元的用法主要有三种:全局函数做友元、类做友元、最后是成员函数做友元。在这我主要讨论类做友元和成员函数做友元这两个,我感觉全局函数做友元其实是比较简单的,只要将全局函数的声明放到想做友元类的里面就可以。NOTE:友元的声明是不会受到private public protected的影响的,但是尽量统一放到一起。

1.类做友元

类class是C++面向对象语言重要的部分,类可以将数据函数进行封装,但是如果一个类A想访问另一个类B的话怎么办呢啊??也不能说让我看看你的类有啥把,太粗鲁了!我们是文明人,想访问它的成员得成为它的好朋友!!哈哈,让我看看 。那么首先声明一个类叫做屏幕类Screen,你别的别管,就只需知道这个类负责在屏幕上可以显示一些东西就可以,具体的代码不用理解,那首先Sceen上场;


```cpp
class Screen
{
public:
	//一些代码
private:
	typedef std::string::size_type pos;
	pos m_cursor = 0;//光标的位置
	pos m_Height, m_Width = 0;//屏幕的高和宽
	std::string m_Conents;//屏幕上显示的内容呗,能是啥
	///
};

但是我想要个能管理我的窗口类Window,管着我这个Screen,比如最简单的功能就是可以管理指定屏幕Screen的内容消除,行先看看这个Window类把,长什么样子呀!

class Screen;//这里必须提前声明以下,要不下面哪里知道Screen是啥玩意!
class Window
{
public:
	//窗口中每个屏幕的编号
	using screenIndex = std::vector<Screen>::size_type;

	void Clear(screenIndex);
private:
		//我有一个vetor,管理一群Screen对象!
		std::vector<Screen> m_Screens;
}

那么我想访问Screen就得成为它的朋友:

class Screen
{
	friend class Window;//这就完事了!
public:
	//一些代码
private:
	typedef std::string::size_type pos;
	pos m_cursor = 0;//光标的位置
	pos m_Height, m_Width = 0;//屏幕的高和宽
	std::string m_Conents;//屏幕上显示的内容呗,能是啥
	///
};

这样我就可以访问你的类所有私有成员了!比如Window的clear函数:

void Window::Clear(screenIndex i)
{
	//创建某块屏幕的引用
	Screen&s = m_Screens[i];
	//清空某块屏幕的内容
	s.m_Conents = (s.m_Width*s.m_Height, ' ');
}

2.成员函数做友元

其实有些Window类的函数是不需要访问Screen类的成员的,没必要,只要特定的函数才需要,那么这时候就是成员函数做友元,只有某个成员函数需要进行访问!
现在假如让clear()函数成为Screen的友元,接下来的步骤:
1.首先你不得有个Window类把,那么定义一个Window类,这时候声明Clear()函数,记住昂不能定义!你肯定问为甚我不能定义它呀??你定义个锤子,你定义它现在能访问Screen吗?不能,先声明它呗,那你肯定会说,我声明完了让他变成它的友元去!好,下一步就是声明它为Screen友元;
2.声明clear()为友元:

class Screen;
class Window
{
public:
	//窗口中每个屏幕的编号
	using screenIndex = std::vector<Screen>::size_type;
	//Here,这就是声明!!!!!
	void Clear(screenIndex);
private:
		//我有一个vetor,管理一群Screen对象!
		std::vector<Screen> m_Screens;
}
class Screen
{
	friend void Window::Clear(screenIndex);
public:
	//一些代码
private:
	typedef std::string::size_type pos;
	pos m_cursor = 0;//光标的位置
	pos m_Height, m_Width = 0;//屏幕的高和宽
	std::string m_Conents;//屏幕上显示的内容呗,能是啥
	///
};

成员函数做友元的时候,一定说明它的作用域,要不别人伪装成clear()怎么办!
3.最后一步你就可以对clear()进行定义了:

void Window::Clear(screenIndex i)
{
	//创建某块屏幕的引用
	Screen&s = m_Screens[i];
	//清空某块屏幕的内容
	s.m_Conents = (s.m_Width*s.m_Height, ' ');
}

其次我在强调这个友元声明的问题:
在这里插入图片描述
建议大家动手试下!!

全部代码放一下:
头文件:

#pragma once
#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Screen;//2.因为window需要Screen,所以必须进行声明一下!!
class Window
{
public:
	//窗口中每个屏幕的编号
	using screenIndex = std::vector<Screen>::size_type;
	//1.成员函数做Screen的友元,在这里不能进行定义[friend]
	void Clear(screenIndex);
private:
	
	//std::vector<Screen> m_Screens{ Screen(24,80,' ') };
	std::vector<Screen> m_Screens;
};//当我们提供一个类内初始值的时候,必须以符号=或者花括号{}表示


class Screen
{
	//friend class Window;
	
	using screenIndex = std::vector<Screen>::size_type;
	//3友元声明  4.友元定义[可以被定义在这个地方]
	friend void Window::Clear(screenIndex);//window::clear(screenIndex);之前必须被声明过了

public:
	typedef std::string::size_type pos;
	Screen() = default;
	Screen(pos ht,pos wd,char c):m_Height(ht),m_Width(wd),m_Conents(ht*wd,c)
	{
	}
	Screen(pos ht, pos wd) :m_Height(ht), m_Width(wd), m_Conents(ht*wd,' ')
	{
	}
	//设置光标处的字符
	Screen& Set(char c);
	Screen& Set(pos ht ,pos wd,char c);
	//返回光标处的字符
	 const char& Get() const { return m_Conents[m_cursor]; }
	//得到指定位置的字符:
	const char& GetChar(pos ht,pos wd)const;
	char& GetChar(pos ht, pos wd);
	//
	Screen& move(pos r,pos c);
	void SomeMember()const;

	//打印screen的内容
	const Screen& Display(std::ostream& outPut) const;
	Screen& Display(std::ostream& outPut);
private:
	void DoDisplay(std::ostream &os)const;
private:
	pos m_cursor = 0;//光标的位置
	pos m_Height, m_Width = 0;//屏幕的高和宽
	std::string m_Conents;
	mutable	size_t m_AccessCtr;

};


cpp文件:

```cpp
#include "Screenh.h"
//设置当前光标的元素
Screen & Screen::Set(char c)
{
	m_Conents[m_cursor] = c;
	return (*this);
	// TODO: 在此处插入 return 语句
}

//设置指定行列坐标的元素
Screen & Screen::Set(pos ht, pos wd, char c)
{
	pos row = (ht-1)*m_Width;
	m_Conents[row + (wd-1)] = c;
	return (*this);
	// TODO: 在此处插入 return 语句
}
//获取指定行列坐标的元素
const char& Screen::GetChar(pos ht, pos wd) const//ht代表高度 wd代表宽度
{
	return m_Conents[(ht - 1)*m_Width +(wd-1)];
}

char& Screen::GetChar(pos ht, pos wd)
{
	return m_Conents[(ht - 1)*m_Width + (wd - 1)];
}

//更新当前光标的位置
Screen& Screen::move(pos r, pos c)//row:行 col: 列
{
	pos row =( r-1)*m_Width;//计算行的位置
	m_cursor = row + (c-1);//将行内光标移动到指定的列[都是从00开始呢啊吧]
	return *this;
	// TODO: 在此处插入 return 语句
}

void Screen::SomeMember() const
{
	++m_AccessCtr;
}

const Screen & Screen::Display(std::ostream & outPut) const
{
	DoDisplay(outPut);
	return *this;

	// TODO: 在此处插入 return 语句
}

Screen & Screen::Display(std::ostream & outPut)
{
	DoDisplay(outPut);
	return *this;
	// TODO: 在此处插入 return 语句
}

void Screen::DoDisplay(std::ostream & os) const
{
	for (pos i=0;i<m_Height*m_Width;i++)
	{
		os << m_Conents[i];
		if (((i+1)%(m_Width))==0)
		{
			os << "\n";
		}
		
	}
}
/*
*@brief 负责把指定的Screen内容设为空白
*
*@param screenIndex:指定屏幕的编号
*/

void Window::Clear(screenIndex i)
{
	//创建某块屏幕的引用
	Screen&s = m_Screens[i];
	//清空某块屏幕的内容
	s.m_Conents = (s.m_Width*s.m_Height, ' ');
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值