本文最后更新于:1 年前
(一)引言:
类具有封装和信息隐藏的特性,只有类的成员函数能够访问类的私有成员,程序中其他的函数在一般情况下是无法访问私有成员的。
然而,有些时候,类要求自己的成员可对部分外部函数/类可见,如果将其内部数据成员和成员函数均声明为公有的,会破坏类隐藏的特性。另外,对某些成员函数多次调用时,由于参数传递、类型检查和安全性检查等需要时间开销,定义过多的成员函数会影响程序的运行效率。
因此,为了解决上述问题,需要在类中声明友元——为了让非成员函数/类即普通函数/类能够访问类的私有成员。
(二)概念:
友元是一种定义在类外部的普通函数或类或类的成员函数,需要在类的体内进行声明。
友元的关键字为 friend,在声明时加在需要设为友元的类/函数头前。
友元本身不是成员函数,但可以访问类中的私有成员,与成员函数的特权相同。
友元能够提高程序的运行效率,但是它破坏了类的封装性和隐蔽性,需要谨慎使用。
(三)特性:
-
友元只能出现在类的定义中。
-
友元只能通过其所在类的对象访问它所在类的成员。
-
友元关系是单向的,不具有交换性,即A是B的友元,但B不一定是A的友元。
-
友元关系不具有传递性,即A是B的友元,B是C的友元,但是C不一定是A的友元。(以声明为准)
-
友元的声明位置在类中是任意的,不受类访问限定符限制。
-
友元函数不能用const修饰,也没有this指针。
-
一个函数/类可以是多个类的友元函数。
-
友元的成立是由这个类来决定的。
(四)分类:
1.普通函数做友元:
多用于运算符重载(详见c++类——运算符重载)。
形式为:类内 friend 返回类型 函数名(参数表) ;
类外 返回类型 函数名(参数表) { 函数体}
参数表内一定有类的值传递/引用传递/地址传递(用于访问类的私有成员,要不然定义它为友元干嘛呢)。
2.类做友元:
友元类中所有的成员函数均为友元函数。
编译器对格式有严格要求:
-
首先对友元类进行前置声明(有些编译器可以省略,会自动补全)。
-
然后定义要声明友元类的一般类,此时在其中可以将友元类声明为友元。
-
最后定义友元类本身,因为前面对声明友元类的一般类进行了定义,此时可以在其中访问一般类的私有数据成员。
即按声明友元类——定义一般类——定义友元类的顺序进行,一般类要声明友元,友元类可以访问一般类的私有数据成员。
3.类的成员函数做友元:
声明时要在函数名前加上类名::(是成员函数所在类)。
编译器对其格式要求更加严格。
-
首先对一般类进行前置声明(在成员函数做友元时此句绝对不可以省略)。
-
然后对含友元函数的类进行定义。此时,要被用于作为友元函数的成员函数只进行声明,不进行定义。成员函数的参数表一定有一般类的值/引用/指针用于访问其私有成员。
-
定义一般类,声明友元函数(做友元函数的成员函数所在类类名一定要加上)。
-
定义做友元函数的成员函数(在其所在类的类外),因为前面的三步,此时才可以访问一般类的私有成员。
(五)代码实现:
1.普通函数做友元:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include<iostream> #include<cmath> using namespace std; class Point { friend double Distance(Point& a, Point& b); private: double x, y; public: Point() { x = 0; y = 0; } Point(double x, double y) { this->x = x; this->y = y; } void move(double x, double y) { this->x = x; this->y = y; } double getX() { return x; } double getY() { return y; } ~Point() { } }; double Distance(Point& a, Point& b) { double temp1 = a.x - b.x; double temp2 = a.y - b.y; return sqrt(temp1 * temp1 + temp2 * temp2); } double Distance2(Point& a, Point& b) { double temp1 = a.getX() - b.getX(); double temp2 = a.getY() - b.getY(); return sqrt(temp1 * temp1 + temp2 * temp2); } int main() { Point* p1 = new Point(1.0, 2.0); Point* p2 = new Point(2.0, 3.0); Point* p3 = new Point(2.0, 3.0); double d1 = Distance(*p1, *p2); double d2 = Distance(*p1, *p3); cout << d1 << endl << d2 << endl; delete p1; delete p2; delete p3; return 0; }
|
2.类做友元:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include<iostream> using namespace std; class Date; class Time { friend class Date; private: int hour; int minute; int second; public: Time(int i1, int i2, int i3) :hour(i1), minute(i2), second(i3) {} Time() { hour = minute = second = 0; } void display() { cout << hour << ":" << minute << ":" << second << endl; return; } }; class Date { private: int year; int month; int day; Time t; public: Date(){ year = month = day = 0; } Date(int i1, int i2, int i3) :year(i1), month(i2), day(i3){} void display() { cout << year << ":" << month << ":" << day << ":"; cout << t.hour << ":" << t.minute << ":" << t.second << endl; return; } void settime(int i1, int i2, int i3) { t.hour = i1, t.minute = i2, t.second = i3; return; } }; int main() { Date d; d.display(); d.settime(1, 2, 3); d.display(); return 0; }
|
3.类的成员函数做友元:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include<iostream> using namespace std; class Time; class Date { private: int year; int month; int day; public: Date() { year = month = day = 0; } Date(int i1, int i2, int i3) :year(i1), month(i2), day(i3) {} void display(Time& t); void settime(int i1, int i2, int i3, Time& t); }; class Time { friend void Date::settime(int i1, int i2, int i3, Time& t); friend void Date::display(Time &t); private: int hour; int minute; int second; public: Time(int i1, int i2, int i3) :hour(i1), minute(i2), second(i3) {} Time() { hour = minute = second = 0; } void display() { cout << hour << ":" << minute << ":" << second << endl; return; } }; void Date::display(Time& t) { cout << year << ":" << month << ":" << day << ":"; cout << t.hour << ":" << t.minute << ":" << t.second << endl; return; } void Date::settime(int i1, int i2, int i3, Time& t) { t.hour = i1, t.minute = i2, t.second = i3; return; } int main() { Date d; Time t; d.display(t); d.settime(1, 2, 3,t); d.display(t); return 0; }
|