根据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的博客-CSDN博客中,就有构造函数定义和声明的使用格式)
如果没有类型说明,那么构造函数相当于还在给类的(公有,私有)成员变量赋初值,
而加上了类型说明,那么相当于构造函数在给函数内自定义的变量赋初值,和类里面的成员没有关系,而类的成员实际上并没有被赋值,输出时返回的自然就是一个随机值;所以,我们应将程序改为:(通过实参形参调用传值)
#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的博客-CSDN博客
(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的博客-CSDN博客:#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;
}