C语言日记 37 类的友元(友元类见下一篇)

本文详细介绍了C++中友元的概念及其应用,包括全局函数、成员函数作为友元的情况,并探讨了不同方式下如何访问类的私有成员。此外,还讲解了如何使用友元进行两点间距离的计算。

(1):全局函数做友元 

根据36 类和对象-友元-全局函数做友元_哔哩哔哩_bilibili复现出如下代码:

一、(只是)访问(公开)内部成员:

#include <iostream>
using namespace std;
class Building
{
private:
	int ws;//卧室
public:
	int kt;//客厅
	Building();
};
Building::Building()//构造函数赋初值
	{
		int ws = 1;
		int kt = 2;
	}
int visit(Building b)
{

	cout << "客厅=" << b.kt << endl;
	return 0;
}
int main()
{
	Building b1;
	visit(b1);
}

在这里,实际上,我们也可以把构造函数写在类里面,实现同样的效果:

class Building
{
private:
	int ws;//卧室
public:
	int kt;//客厅
	Building()//构造函数赋初值
	{
		int ws = 1;
		int kt = 2;
	}
};

 结果:

为什么我写了半天,最后返回的是一个随机值呢?

根本原因,就在于构造函数的格式不对,构造函数在赋初值时,类里面的变量(成员)前不应该(不能)有类型说明

C语言日记 33 构造函数_宇 -Yu的博客-优快云博客中,就有构造函数定义和声明的使用格式)

如果没有类型说明,那么构造函数相当于还在给类的(公有,私有)成员变量赋初值,

而加上了类型说明,那么相当于构造函数在给函数内自定义的变量赋初值,和类里面的成员没有关系,而类的成员实际上并没有被赋值,输出时返回的自然就是一个随机值;所以,我们应将程序改为:(通过实参形参调用传值)

#include <iostream>
using namespace std;
class Building
{
private:
	int ws;//卧室
public:
	int kt;//客厅
	Building();
};
Building::Building()//构造函数赋初值
{
	 ws = 1;
	 kt = 2;
}
int visit(Building b)
{

	cout << "客厅=" << b.kt << endl;
	return 0;
}
int main()
{
	Building b1;
	visit(b1);
}

结果:

修改为36 类和对象-友元-全局函数做友元_哔哩哔哩_bilibili源程序所设计的各个模块的样子:

#include <iostream>
using namespace std;
class Building
{
private:
	int ws;//卧室
public:
	int kt;//客厅
	Building()//构造函数赋初值
	{
		ws = 1;
		kt = 2;
	}
};
//
int visit(Building b)
{
	cout << "客厅=" << b.kt << endl;
	return 0;
}
void test()
{
	Building b1;
	visit(b1);
}
int main()
{
	test();
}

我们可以通过实参形参调用传值,也可以用指针,引用的方式传值:

指针:

int visit(Building* b)
{
	cout << "客厅=" << b->kt << endl;
	return 0;
}
void test()
{
	Building b1;
	visit(&b1);
}

注解:

(1):这里的“->”,表示:通过指针来访问结构体变量(的具体内容)C语言日记 28 结构体类型_宇 -Yu的博客-优快云博客

(2):

visit(&b1);

中,&表示取(地)址,不能改为*(如果改为*,则表示访问该指针指向的目标对象的具体内容)

如果一定不想这样写的话,可以改写为:

void test()
{
	Building b;
	Building *b1=&b;
	visit(b1);
}

引用:

int visit(Building &b)
{
	cout << "客厅=" <<b.kt << endl;
	return 0;
}
void test()
{
	Building b;
	visit(b);
}

注解:

(1):引用访问,就和对象访问自身的内容属性引用,不能用“->”;(“->”只能用于指针)

(2):

	visit(b);

只能这么写,不能在前面加“*”(加了表求指向目标的值),也不能加“&”(加了表求指向目标的地址)

二、访问内部私有成员(这就要用到友元了)

这时,既然我们想要让全局函数访问内部私有成员,只要在前面的基础上

在visit()函数中写一个输出私有函数的语句:

    cout << "卧室=" << b.ws << endl;

并且在类的成员声明里面加(上)一个友元函数的声明:

    friend void visit(Building b);

值得注意的是:

这里的友元函数的声明加在类(体)的任意处都可以:

友元函数不是成员函数,无论是放在private私有成员说明中:

#include <iostream>
using namespace std;
class Building
{
private:
	int ws;//卧室
	friend void visit(Building b);
public:
	int kt;//客厅
	Building()//构造函数赋初值
	{
		ws = 1;
		kt = 2;
	}
};
//
void visit(Building b)
{
	cout << "客厅=" << b.kt << endl;
	cout << "卧室=" << b.ws << endl;
}
void test()
{
	Building b1;
	visit(b1);
}
int main()
{
	test();
}

还是放在成员说明之外:

#include <iostream>
using namespace std;
class Building
{
	friend void visit(Building b);
private:
	int ws;//卧室
public:
	int kt;//客厅
	Building()//构造函数赋初值
	{
		ws = 1;
		kt = 2;
	}
};
//
void visit(Building b)
{
	cout << "客厅=" << b.kt << endl;
	cout << "卧室=" << b.ws << endl;
}
void test()
{
	Building b1;
	visit(b1);
}
int main()
{
	test();
}

最终结果都可以访问类的内部私有成员:

例8-14 使用普通函数计算两点间的距离。

源程序:

#include <iostream>
#include <cmath>
using namespace std;
class Point	//Point 类定义
{
private://私有数据成员
	int x, y;
public://外部接口
	Point(int x = 0, int y = 0) :x(x), y(y) { }
	int getX() { return x; }
	int getY() { return y; }
	friend float dist(Point& a, Point& b); //友元函数是一个普通函数
};
float dist(Point& a, Point& b)//普通函数的定义
{
	double x = a.x - b.x;
	double y = a.y - b.y;
	return(float)sqrt(x * x + y * y);
}
//
int main()
{
	Point p1(3, 5), p2(11, 6);
	cout << "The distance is:";
	cout << dist(p1, p2) << endl;
	//调用普通友元函数
	return 0;
}

结果:

The distance is:8.06226

(1):#include <cmath>:相当于#include <math.h> (C语言)<C++的库>,当然这里不写也无所谓,如同:C语言日记 8 C++语句_宇 -Yu的博客-优快云博客:#include <math.h>//可有可无

(2):其中的: friend float dist(Point &a, Point &b); 只是一个用引用作为函数参数的形式,可以改(写)为:(实参形参传递数据)

friend float dist(Point a, Point b);  

详见书P105(当然,像这样用实参形参传递数据,采用的是值传递的传值的方式);

也可以改(写)为:(指针传递数据)

#include <iostream>
#include <cmath>
using namespace std;
class Point	//Point 类定义
{
private://私有数据成员
	int x, y;
public://外部接口
	Point(int x = 0, int y = 0) :x(x), y(y) { }
	int getX() { return x; }
	int getY() { return y; }
	friend float dist(Point* a, Point* b); //友元函数是一个普通函数
};
float dist(Point* a, Point* b)//普通函数的定义
{
	double x = a->x - b->x;
	double y = a->y - b->y;
	return(float)sqrt(x * x + y * y);
}
//
int main()
{
	Point p1(3, 5), p2(11, 6);
	cout << "The distance is:";
	cout << dist(&p1, &p2) << endl;
	//调用普通友元函数
	return 0;
}

 当然,改写为指针传递数据的方式的修改过程,比起其他两种情况要更为复杂一些:

改动处:

(1):形参a和b改为指针

(2):“->”改为"."

(3):调用dist函数时,里面的实参p1,p2改为取(地)址“&p1,&p2”

(3):另外,(如果)我们想要在类中(里面)定义该友元函数(不用分开声明,直接一次性定义完成就行了)最终结果也一样:

#include <iostream>
using namespace std;
class Point	//Point 类定义
{
private://私有数据成员
	int x, y;
public://外部接口
	Point(int x = 0, int y = 0) :x(x), y(y) { }
	int getX() { return x; }
	int getY() { return y; }
	friend float dist(Point a, Point b)//友元函数是一个普通函数
	{
		double x = a.x - b.x;
		double y = a.y - b.y;
		return(float)sqrt(x * x + y * y);
	}
};
//
int main()
{
	Point p1(3, 5), p2(11, 6);
	cout << "The distance is:";
	cout << dist(p1, p2) << endl;
	//调用普通友元函数
	return 0;
}

而在这里我们可以看到,实际上想要访问本类的内部私有成员,根本还用不着什么友元函数,

直接设立一个公有的类函数直接访问调用私有成员就可以:

#include <iostream>
#include <cmath>
using namespace std;
class Point	//Point 类定义
{
private://私有数据成员
	int x, y;
public://外部接口
	Point(int x = 0, int y = 0) :x(x), y(y) { }
	int getX() { return x; }
	int getY() { return y; }
	float dist(Point* a, Point* b)//普通函数的定义
	{
		double x = a->x - b->x;
		double y = a->y - b->y;
		return(float)sqrt(x * x + y * y);
	}
};
//
int main()
{
	Point p1(3, 5), p2(11, 6);
	cout << "The distance is:";
	cout << dist(&p1, &p2) << endl;
	//调用普通友元函数
	return 0;
}

结果:

为什么???

调用类中定义的函数必须用对象(才能调用):(这里用p1,p2都可以)

#include <iostream>
#include <cmath>
using namespace std;
class Point	//Point 类定义
{
private://私有数据成员
	int x, y;
public://外部接口
	Point(int x = 0, int y = 0) :x(x), y(y) { }
	int getX() { return x; }
	int getY() { return y; }
	float dist(Point* a, Point* b)//普通函数的定义
	{
		double x = a->x - b->x;
		double y = a->y - b->y;
		return(float)sqrt(x * x + y * y);
	}
};
//
int main()
{
	Point p1(3, 5), p2(11, 6);
	cout << "The distance is:";
	cout << p1.dist(&p1, &p2) << endl;
	//调用普通友元函数
	return 0;
}

 (2):成员函数做友元

 例8-15 使用其他类的成员函数实现两点间距离的计算。

源程序:

#include <iostream>
using namespace std;
class Point;//声明 Point 类
class Dist//Dist 类定义
{
public:
	float dist(Point& a, Point& b);
};
class Point//Point 类定义
{
private://私有数据成员
	int x, y;
public://外部接口
	Point(int x = 0, int y = 0) :x(x), y(y) {}
	int getx() { return x; }
	int getY() { return y; }
	friend float Dist::dist(Point& a, Point& b);
	//友元函数是Dist的成员函数
};
float Dist::dist(Point& a, Point& b) //友元函数的定义
{
	double x = a.x - b.x;
	double y = a.y - b.y;
	return (float)sqrt(x * x + y * y);
}
int main()
{
	Point p3(10, 8), p4(4, 12);
	Dist d;
	cout << "The distance is:"; cout << d.dist(p3, p4) << endl;
	//调用成员友元函数
	return 0;
}

The distance is:7.2111

 ​​

(3):友元类

见下一篇日记

(其实是下一篇日记太短,而这篇日记太长,把这个内容换一个位置,调整一下两篇的篇幅)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值