C++面向对象:友元函数和友元类

1.友元函数

1.1 外部函数访问类内成员

class person
{
public:
	string name;
private:
	int age;
protected:
	int height;
};

void print(person& a)
{	
	cout<<a.name<<endl;

	//访问出错,不可访问protected和private
	//cout<<a.age<<endl;
	//cout<<a.height<<endl;
}

对于上面的person类,内部有privateprotectedpublic的三类访问权限的成员。写一个外部函数print()来打印这三类成员,则print()可以访问public的,但是protectedprivate的无法访问。

如果我们要让print()也可以访问protectedprivate的成员,方法之一就是将print()挪到print()类内部使其成为成员函数,但是这样print()就不是外部函数了,这个时候这个方法就不合适了。而友元函数可以解决上面说的问题。

1.2 友元函数的引入

对于上面的需求:在外部函数访问内部私有或者保护成员,可以通过将外部函数print()声明为print()类的友元函数来解决。语法上的要求是将该函数在类内声明,声明需要加上friend关键字修饰,

举个栗子:

class person
{
public:
	string name;
	//声明友元函数
	friend void print(person&a);
	person(){};
	person(string name,int age,int height)
	{
		this->name=name;
		this->age=age;
		this->height=height;
	}
private:
	int age;
protected:
	int height;
};

void print(person& a)
{	
	cout<<a.name<<endl;

	//声明为友元函数后可以访问protected和private
	cout<<a.age<<endl;
	cout<<a.height<<endl;
}

1.3 友元函数总结

  • 1.友元函数不是本类的成员函数,而是一个外部函数。
  • 2.友元函数的标志就是在类内部加friend关键字来声明。
  • 3.友元函数声明的位置不要求,写在private或者protected或者public内都可以,反正只要有声明就行。
  • 4.一个外部函数成为类的友元后,访问权限被扩展到等同于类的内部成员函。
  • 5.友元函数是单向的,反过来是不行的。
  • 6.友元函数就好像在类的封装和访问权限保护上打了个“洞”,所以是对面向对象的一种破坏,所以不能滥用。

2.友元函数的另一种实现

友元函数的一种实现就是上面需求中的外部函数。

友元函数的另一种实现为:在另一个类中的成员函数(也叫友元成员,友元成员方法,友元成员函数)

#include<iostream>
#include<string>

using namespace std;

//类的前置声明
class food;

class person
{
public:
	string name;
	person(){};
	person(string name):name(name){};
	void eat(food&tmp);	
};

class food
{
public:
	string name;
	food(){};
	food(string name):name(name){};
	
	friend void person::eat(food&tmp);
private:
	int x;
protected:
	int y;
};
void person::eat(food&tmp)
{
	//可以直接访问public的name
	cout<<this->name<<" eat a "<<tmp.name<<endl;
	
	//不可以直接访问private和protected,需要在food类内声明友元
	cout<<tmp.name<<" x="<<tmp.x<<endl;
	cout<<tmp.name<<" y="<<tmp.y<<endl;
	
}

int main(void)
{
	person tom("tom");
	food cake("cake");
	
	tom.eat(cake);
	
	return 0;
}
  • 类的前置声明:
    两个类要互相引用,编译的时候就会出现其中一个未定义的错误,把谁写在前面就会报另一个未定义,此时可以用前置声明来解决。前置声明不包括类的详细信息,所以编译器无法得到前置声明类成员等详细信息。
    不能试图通过前置声明解决类成员的调用,因为前置声明只针对类的整体,不涉及内部细节,所以使用细节的时候编译器不知道如何下手就会报错。不能试图通过前置声明来定义类的对象,只能改为定义类对象的指针,因为不管类内部的细节是什么样的,指针都是一样的。

总结:
理解编译器的工作原理和“脾气”,很多事自然就很简单了。在设计多个类的体系时,尽量设计好层次关系成单向的,尽量避免互相引用的情况

3.友元类

3.1 友元类的概念和使用

将类A声明为B中的友元类后,则A中所有成员函数都成为类B的友元函数了。要注意:友元类的定义和使用友元类是单向的。

举个栗子:

#include<iostream>
#include<string>

using namespace std;

class food
{
public:
	string name;
	food(){};
	food(string name):name(name){};
	
	//在food类中声明友元类person
	friend class person;

private:
	int x;
protected:
	int y;
};

class person
{
public:
	
	string name;
	person(){};
	person(string name):name(name){};
	void eat(food&tmp)
	{
		//则在person中所有方法都是food的友元函数,可以访问food所以成员变量
		cout<<this->name<<" eat a "<<tmp.name<<endl;	
		cout<<tmp.name<<" x="<<tmp.x<<endl;
		cout<<tmp.name<<" y="<<tmp.y<<endl;
		
	}
	
};

int main(void)
{
	person tom("tom");
	food cake("cake");
	
	tom.eat(cake);
	
	return 0;
}

3.2 互为友元类

两个个类可以互为友元类,互为友元类要注意互相引用的细节规则。

3.3 友元类总结

  • 1.友元类其实就是批量制造友元函数。友元类中所有全部成员都成为了友元函数,相当于一次打了很多洞,极大破坏了面向对象。
  • 2.除非确实有必要,否则建议按需定义友元函数,尽量维护面向对象,让代码更安全健壮。

4.为什么会有友元函数

4.1 使用友元函数的优缺点

  • 缺点:破坏了封装机制,尽量不使用友元函数,不得已才使用友元函数。
  • 优点:在实现类之间数据共享时,减少系统开销,提高效率。

4.2 使用友元函数的两种情况

  • 1.运算符重载的某些场合需要使用友元。
  • 2.两个类要共享数据的时候需要使用友元。

4.3 运算符重载中使用友元回顾

运算符重载使用方法参考:[C++学习笔记:运算符重载]

并非所有运算符重载都可用友元函数,有四个运算符 =, ->, [], ()就不可以。

4.4 两个类如何共享数据

类内的数据其实就是类的成员变量。

2个类共享数据方法(准确的说是两个对象交换数据):

  • 1.将共享数据访问权限设置为public
  • 2.通过第三个专门封装数据的类,和2个类中带参数的成员函数来传参共享。
  • 3.通过友元函数打洞。

4.5 友元函数和类的成员函数的区别

  • 1.成员函数有 this指针而友元函数没有,这是因为友元只是朋友并不是类内“自家人”。
  • 2.友元函数是不能被继承的,就像父亲的朋友未必是儿子的朋友。
  • 3.友元关系不具有传递性。类B是类A的友元,类C是B的友元,类C不一定是类A的友元,要看类中是否有相应的声明。

4.6 共有友元函数

  • 1.1个函数可以同时成为2个类的友元函数。
  • 2.共有友元函数可以是外部函数,也可以是某个(第3个)类的成员函数。
  • 3.共有友元函数内可同时访问2个类的受保护成员,间接将2个完全无关的类的数据打通了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【为什么还需要学习C++?】 你是否接触很多语言,但从来没有了解过编程语言的本质?你是否想成为一名资深开发人员,想开发别人做不了的高性能程序?你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹? 那么C++就是你个人能力提升,职业之路进阶的不二之选。【课程特色】 1.课程共19大章节,239课时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。2.带你从知识与思想的层面从0构建C++知识框架,分析大型项目实践思路,为你打下坚实的基础。3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》课程。【学完后我将达到什么水平?】 1.对C++的各个知识能够熟练配置、开发、部署;2.吊打一切关于C++的笔试面试题;3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。【面向人群】 1.希望一站式快速入门的C++初学者; 2.希望快速学习 C++、掌握编程要义、修炼内功的开发者; 3.有志于挑战更高级的开发项目,成为资深开发的工程师。 【课程设计】 本课程包含3大模块基础篇本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。进阶篇本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。提升篇:本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值