【C++的面向对象】------- C++的友元函数和友元类


1.什么是友元函数


【1】外部函数访问类内成员

  • 写一个Person类,内部有private、protected、public的三类访问权限的成员
  • 写一个外部函数disp_info来打印这三类成员
#include <iostream>
using namespace std;

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

//构造函数
person::person(int age,int height,string name)
{
	this->age = age;
	this->height = height;
	this->name = name;
}

//类外的函数
void disp_info(person& pn)
{
	cout << "age = " << pn.age << endl;            //public的,类外可以访问
	cout << "height = " << pn.height << endl;      //protected的,类外不可以访问
	cout << "name = " << pn.name << endl;          //private的,类外不可以访问
}

int main(int argc, char const *argv[])
{
	person p1(10,155,"jime");
	disp_info(p1);

	return 0;
}

在这里插入图片描述

  • 总结:可以访问public的,但是protected和private的无法访问
  • 想办法:除非把disp_info挪到Person类内部成为成员函数,否则没办法

【2】友元函数的引入

  • 将外部函数disp_info声明为Person类的友元函数即可解决
class person
{
public:
	int age;
	person(){};
	person(int age,int height,string name);

	//声明外部函数为类的友元函数
	friend void disp_info(person& pn);
protected:
	int height;
private:
	string name;	
};

在这里插入图片描述

【3】总结

  • 友元函数不是本类的成员函数,而是一个外部函数
  • 友元函数的标志就是在类内部加friend关键字来声明
  • 友元函数声明的位置不要求,写在private或者protected或者public内都可以,反正只要有声明就行
  • 一个外部函数成为类的友元后,访问权限被扩展了,等同于类的内部成员函数了
  • 友元函数是单向的。例如一个类A外部有函数fun(),函数里有一个局部变量i;当fun()函数声明为A的友元函数,意为着fun()函数能访问类A里面的所有权限的成员,而类A却不能访问函数fun()里面的变量i
  • 友元函数就好像在类的封装和访问权限保护上打了个“洞”,所以是对面向对象的一种破坏,所以不能滥用

2.友元函数的第二种实现


【1】友元函数的2种实现

  • 友元函数为外部函数(上面已经实现)
  • 友元函数为另一个类中的成员函数(也叫友元成员,友元成员方法,友元成员函数)
//- 友元函数为另一个类中的成员函数的实现代码
#include <iostream>
using namespace std;

class person;      //类的前置声明

class animal
{
public:
	void eat(person& pn);    //这里只用到一个person类的引用,不涉及person里面的具体细节,所以能编译通过
};

class person
{
public:
	int age;
	person(){};
	person(int age,int height,string name);

	friend void animal::eat(person& pn);
protected:
	int height;
private:
	string name;	
};

//构造函数
person::person(int age,int height,string name)
{
	this->age = age;
	this->height = height;
	this->name = name;
}

void animal::eat(person& pn)
{
	cout << "animal eat a person nameed" << pn.name << endl;
	cout << "animal eat a person age = " << pn.age << endl;
	cout << "animal eat a person height = " << pn.height << endl;
}

int main(int argc, char const *argv[])
{
	person p1(10,155,"jime");
	animal a1;
	a1.eat(p1);

	return 0;
}

在这里插入图片描述

【2】类的前置声明

  • 两个类要互相引用,就会出现“未定义”尴尬,此时可以用前置声明来解决
  • 前置声明不包括类的详细信息,所以编译器无法得到前置声明类的大小,成员等详细信息
  • 不能试图通过前置声明解决类成员的调用
class animal;      //类的前置声明

class person
{
public:
	int age;
	person(){};
	person(int age,int height,string name);

	friend void animal::eat(person& pn);     //编译报错,不能通过animal类的前置声明就调用animal里面的eat()成员
protected:
	int height;
private:
	string name;	
};

class animal
{
public:
	void eat(person& pn);    
};

在这里插入图片描述

  • 不能试图通过前置声明来定义类的对象,只能改为定义类对象的指针或引用
class person;      //类的前置声明

class animal
{
public:
	void eat(person& pn);    //这里只用到一个person类的引用,不涉及person里面的具体细节,所以能编译通过
	//person p1;             //不可以
	person *p2;              //定义成指针和引用都可以
};

class person
{
public:
	int age;
	person(){};
	person(int age,int height,string name);

	friend void animal::eat(person& pn);
protected:
	int height;
private:
	string name;	
};

3.友元类


【1】友元类的概念和使用

#include <iostream>
using namespace std;

class person;      //类的前置声明

class animal
{
public:
	void eat(person& pn);    
	void love(person& pn); 
};

class person
{
public:
	int age;
	person(){};
	person(int age,int height,string name);

	friend class animal;       //将animal整个类声明为person类的友元类
protected:
	int height;
private:
	string name;	
};

//构造函数
person::person(int age,int height,string name)
{
	this->age = age;
	this->height = height;
	this->name = name;
}

void animal::eat(person& pn)
{
	cout << "animal eat a person nameed" << pn.name << endl;
	cout << "animal eat a person age = " << pn.age << endl;
	cout << "animal eat a person height = " << pn.height << endl;
	cout << endl;
}

void animal::love(person& pn)
{
	cout << "animal love a person nameed" << pn.name << endl;
	cout << "animal love a person age = " << pn.age << endl;
	cout << "animal love a person height = " << pn.height << endl;
}

int main(int argc, char const *argv[])
{
	person p1(10,155,"jime");
	animal a1;
	a1.eat(p1);
	a1.love(p1);

	return 0;
}

  • 将类animal声明为person中的friend class后,则animal中所有成员函数都成为类person的友元函数了
  • 友元类是单向的;2个类可以互为友元类

【2】友元类总结

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

4.关于友元函数


【1】使用友元函数的优缺点

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

【2】使用友元函数的两种情况

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

【3】运算符重载中使用友元

#include <iostream>

using namespace std;

class coordinate
{
public:
	int x;					// x轴坐标
	int y;					// y轴坐标
	
	coordinate();
	coordinate(int x0, int y0);
	
	// 拷贝构造函数
	coordinate(const coordinate& rhs);
	
	void print(void);
	
	friend coordinate operator+(const coordinate& a, const coordinate& b);
	
};

coordinate::coordinate()
{
	x = 0;
	y = 0;
};

coordinate::coordinate(int x0, int y0)
{
	x = x0;
	y = y0;
};

// 拷贝构造函数
coordinate::coordinate(const coordinate& rhs)
{
	cout << "---copy construtor---" << endl;
	this->x = rhs.x;
	this->y = rhs.y;
}

void coordinate::print(void)
{
	cout << "(" << this->x << ", " << this->y << ")" << endl;
}

// 用独立函数来实现+的运算符重载
coordinate operator+(const coordinate& a, const coordinate& b)
{
	coordinate tmp;
	
	tmp.x = a.x + b.x;
	tmp.y = a.y + b.y;
	
	return tmp;
}


int main(void)
{
	coordinate a(1, 3);
	coordinate b(2, 4);
	coordinate c;
	
	c = a + b;			//  a+b 就相当于是 c = operator+(a, b);
//	c = b + a;			// 相当于 c = operator+(b, a);
	
	a.print();
	b.print();
	c.print();

	return 0;
}

【4】两个类如何共享数据

  • 类内的数据,其实就是类的成员变量
  • 2个类共享数据方法1:将共享数据访问权限设置为public。
  • 2个类共享数据方法2:通过第三个专门封装数据的类,和2个类中带参数的成员函数来传参共享
  • 2个类共享数据方法3:通过友元函数打洞

【5】友元函数和类的成员函数的区别

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

【6】共有友元函数

  • 1个函数同时成为2个类的友元函数
  • 共有友元函数可以是外部函数,也可以是某个(第3个)类的成员函数
  • 共有友元函数内可同时访问2个类的受保护成员,间接将2个完全无关的类的数据打通了
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值