第28课 - 友元的尴尬能力
1. 什么是友元?
(1)友元是C++ 中的一种关系
(2)友元关系发生在函数与类之间或者类与类之间
(3)友元关系是单向的,不能传递
2. 友元的用法
(1)在类中以 friend 关键字声明友元
(2)类的友元可以是其它类或者具体函数
(3)友元不是类的一部分
(4)友元不受类中访问级别的限制
(5)友元可以直接访问具体类的所有成员
3. 友元的语法
在类中用 friend 关键字对函数或类进行声明。
1 #include <stdio.h> 2 #include <math.h> 3 4 class Point 5 { 6 double x; 7 double y; 8 public: 9 Point(double x, double y) 10 { 11 this->x = x; 12 this->y = y; 13 } 14 15 double getX() 16 { 17 return x; 18 } 19 20 double getY() 21 { 22 return y; 23 } 24 25 friend double func(Point& p1, Point& p2); // 友元函数 26 }; 27 28 double func(Point& p1, Point& p2) 29 { 30 double ret = 0; 31 32 ret = (p2.y - p1.y) * (p2.y - p1.y) + (p2.x - p1.x) * (p2.x - p1.x); 33 34 ret = sqrt(ret); 35 36 return ret; 37 } 38 39 int main() 40 { 41 Point p1(1, 2); 42 43 Point p2(10, 20); 44 45 printf("p1(%f, %f) ", p1.getX(), p1.getY()); 46 printf("p2(%f, %f) ", p2.getX(), p2.getY()); 47 printf("|(p1, p2)| = %f ", func(p1, p2)); 48 49 return 0; 50 }
4. 友元的尴尬
(1)友元是为了兼顾 C 语言的高效而诞生的。
前面的例子中,计算两点之间的距离,如果使用C语言开发,直接访问结构体成员即可,效率很高。使用C++开发,如果按照一般的方式,需要多次调用 public 中的成员函数来访问 private 中的成员变量,该例中就调用了8次 getX() / getY(),这样就导致程序效率很低。早期的C++开发就是使用这种方式,然后被很多程序员所诟病,为了兼顾C语言的高效,由此诞生了友元。
(2)友元直接破坏了面向对象的封装性,很多程序开发者将C++当作C语言使用了,将封装性这样的高级面向对象特性丢失了。
(3)友元在实际产品中的高效是得不偿失的,在现代软件工程开发中已经逐渐被遗弃
5. 注意事项
(1)友元关系不具备传递性。 A 是B 的友元,B 是C 的友元,但A 不 C 的友元。
(2)类的友元可以是其它类的成员函数
(3)类的友元可以是某个完整的类:所有的成员函数都是友元
1 #include <stdio.h> 2 3 class ClassC 4 { 5 private: 6 const char* n; 7 8 public: 9 ClassC(const char* n){this->n = n;} 10 11 friend class ClassB; //B是C的友元类,即B可以任意访问C 12 }; 13 14 class ClassB 15 { 16 private: 17 const char* n; 18 19 public: 20 ClassB(const char* n){this->n = n;} 21 22 void getClassCName(ClassC& c) 23 { 24 printf("c.n = %s ", c.n);//合法,因为在类C中,己将B声明为友元类 25 } 26 27 friend class ClassA; //A是B的友元类,即A可以任意访问B 28 }; 29 30 31 class ClassA 32 { 33 private: 34 const char* n; 35 36 public: 37 ClassA(const char* n){this->n = n;} 38 39 void getClassCName(ClassC& c) 40 { 41 //printf("c.n = %s ", c.n);//非合法,因为在类C中,并没将A声明为友元类 42 } 43 44 void getClassBName(ClassB& b) 45 { 46 printf("b.n = %s ", b.n);//合法,因为在类B中,己将A声明为友元类 47 } 48 }; 49 50 int main() 51 { 52 //A是B的友元类,B是C的友元类,但A不能自动传递为C的友元类 53 ClassA A("A"); 54 ClassB B("B"); 55 ClassC C("C"); 56 57 A.getClassBName(B);//A是B的友元类, 58 B.getClassCName(C);//B是C的友元类 59 60 return 0; 61 }
6. 小结
(1)友元是为了兼顾 C 语言的高效而诞生的
(2)友元直接破坏了面向对象的封装性
(3)友元关系不具备传递性
(4)类的友元可以是其它类的成员函数
(5)类的友元可以是某个完整的类