友元是C++提供的一种破坏数据隐蔽和封装的机制
1.友元函数
友元函数是在类中使用关键字friend修饰的非成员函数
1.1友元普通函数
定义与概念
- 友元函数是一个普通的函数
- 友元普通函数在实现时,不需要类名的限定;在调用时,也不需要由实例来调用
示例代码
#include <iostream> #include <cmath> using namespace std; class Point{ public: Point(int x = 0,int y = 0):x(x),y(y){} int getX(){ return x;}//内联函数 int getY(){ return y;} void showData(); friend float dist(Point &p1,Point &p2);//声明友元函数 private: int x,y; }; //普通成员函数的实现,需要类名限定 void Point::showData(){ cout << "x: " << x << ", y: " << y << endl; } //因为友元函数是非成员函数,所以不需要类名限制 float dist(Point &p1,Point &p2){ double x = p1.x - p2.x; double y = p1.y - p2.y; return static_cast<float>(sqrt(x*x + y*y)); } int main() { Point p1(1,1),p2(4,5); p1.showData(); p2.showData(); //调用友元普通函数时,也不需要由类的实例来调用 cout << "the distance is : " << dist(p1,p2) << endl; return 0; }
1.2友元成员函数
定义与概念
- 友元函数是其它类的成员函数
- 必须先定义包含成员函数的类(比如说A),再在另外一个类(比如说B)中将该成员函数声明为友元函数。此时虽然这个友元函数是A的成员函数,该友元函数仍然称为非成员函数(对于B来说)
示例代码
#include <iostream> #include <cmath> using namespace std; //前向引用声明,否则报错 error: 'Point' does not name a type class Point; class Line{ public: //这时不能使用这样的形式进行初始化:Line(Point p1,Point p2):p1(p1),p2(p2){} //因为此时Point的结构尚未定义,error: field 'p1' has incomplete type Line(Point p1,Point p2); Point& getP1(); //把引用当做函数返回值 Point& getP2(); float dist(); private: //不可以这样定义成员变量:Point p1,p2;因为此时Point结构尚不完善 Point &rp1,&rp2;//类(引用)的组合 }; class Point{ public: Point(int x = 0,int y = 0):x(x),y(y){} int getX(){ return x;}//内联函数 int getY(){ return y;} void showData(); //声明友元成员函数 friend float Line::dist(); private: int x,y; }; void Point::showData(){ cout << "x: " << x << ", y: " << y << endl; } //Line类函数的延迟实现开始 //当一个类的成员变量是引用时,需要在初始化列表中初始化引用 //否则报错:error: uninitialized reference member Line::Line(Point p1,Point p2):rp1(p1),rp2(p2){} Point& Line::getP1(){ return rp1; } Point& Line::getP2(){ return rp2; } float Line::dist(){ double x = rp1.x - rp2.x; double y = rp1.y - rp2.y; return static_cast<float>(sqrt(x*x + y*y)); } //Line类函数的延迟实现结束 int main() { Point p1(1,1),p2(4,5); p1.showData(); p2.showData(); Line line(p1,p2); cout << "the distance is : " << line.dist() << endl; return 0; }
2.友元类
定义与概念
示例代码
#include <iostream> #include <cmath> using namespace std; class Point{ public: Point(int x = 0,int y = 0):x(x),y(y){} int getX(){ return x;}//内联函数 int getY(){ return y;} void showData(); //声明友元类,否则编译不通过,error: 'int Point::x' is private friend class Line; private: int x,y; }; void Point::showData(){ cout << "x: " << x << ", y: " << y << endl; } class Line{ public: Line(Point p1,Point p2):p1(p1),p2(p2){} Point getP1(){ return p1;} Point getP2(){ return p2;} float dist(); private: Point p1,p2;//类的组合 }; float Line::dist(){ double x = p1.x - p2.x; double y = p1.y - p2.y; return static_cast<float>(sqrt(x*x + y*y)); } int main() { Point p1(1,1),p2(4,5); p1.showData(); p2.showData(); Line line(p1,p2); cout << "the distance is : " << line.dist() << endl; return 0; }
3.友元的性质
- 友元关系是不能传递的,如A是B的友元,B是C的友元,但A不是C的友元
- 友元关系是单向的,A是B的友元,A可以访问B的私有属性,反之不成立
- 友元关系是不被继承的,A是B的友元,但A的派生类不是B的友元
4.总结
- 友元是一种破坏数据隐蔽和封装的机制,这是它的用处也是它的坏处。应该尽量避免使用友元
- 示例代码
#include <iostream> #include <cmath> using namespace std; class Point{ public: Point(int x = 0,int y = 0):x(x),y(y){} int getX(){ return x;}//内联函数 int getY(){ return y;} void showData(); float dist(Point p); private: int x,y; }; void Point::showData(){ cout << "x: " << x << ", y: " << y << endl; } //通过这样的方式,可以避免使用友元 float Point::dist(Point p){ double x = p.x - this->x; double y = p.y - this->y; return static_cast<float>(sqrt(x*x + y*y)); } int main() { Point p1(1,1),p2(4,5); p1.showData(); p2.showData(); cout << "the distance is : " << p1.dist(p2) << endl; return 0; }
5.补充
5.1前向声明
- 在C++里面可以声明一个类而不定义它。这个声明被称为前向声明(forward declaration)。
- 在声明之后,定义之前,这个类是一个不完全类型(incompete type),即已知它是一个类型,但不知道包含哪些成员,具有哪些操作。
- 不完全类型只能以有限方式使用,不能定义该类型的对象,不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。
来源:https://www.cnblogs.com/Libinkai/p/10622473.html