C++笔记(4)友元
通常情况下,公有类方法是访问类对象私有部分的唯一途径。除此之外,C++还提供了另外一种形式的访问权限:友元。
友元有三种:
- 友元函数
- 友元类
- 友元成员函数
通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。
1.为何需要友元
Time Time::operator*(double n) const { Time mult; long totalminutes = hours * n * 60 + minutes * n; mult.minutes = totalminutes % 60; mult.hours = totalminutes / 60; return mult; }
上述代码重载了乘法运算符,将一个Time值和一个double值结合在一起。
由于左侧的操作数是调用对象,下面的代码:
A = B * 2.75;
将被转换为下面的成员函数调用:
A = B.operator(2.75);
但是下面的语句:
A = 2.75 * B;
编译器不能使用成员函数调用来替换该表达式。
为了解决该问题我们可以使用非成员函数。非成员函数不是对象调用的,它使用的所有值(包括对象)都是显式参数。这样编译器可以将下面的表达式:
A = 2.75 * B;
与下面的非成员函数匹配:
A = operator(2.75, B);
该函数原型如下
Time operator*(double n,const Time& t);
由于非成员函数无法直接访问类的私有数据,因此引入友元函数。
2.创建友元
第一步:将其原型放在类声明中,并在声明前加上关键字friend
friend Time operator*(double n, const Time& t);
第二步:编写函数定义。不要使用Time::限定符号!不要使用关键字friend!
Time operator*(double n,const Time& t) {
Time mult;
long totalminutes = t.hours * n * 60 + t.minutes * n;
mult.minutes = totalminutes % 60;
mult.hours = totalminutes / 60;
return mult;
}
上面的函数显式地访问t.minutes和t.hours,所以它必须是友元。
下面的版本将Time对象t作为一个整体使用,让成员函数来出路私有值因此不必是友元。
Time operator*(double n,const Time& t){ return t * n; }
3.常用的友元:重载<<运算符
函数原型:
friend std::ostream & operator<<(std::ostream& os, const Time &t);
函数定义
std::ostream & operator<<(std::ostream & os, const Time& t) { os << t.hours << "hours," << t.minutes << "minutes\n"; return os; }
operator<<()函数接受一个ostream参数和一个Time参数,表面看起来它必须同时是两个类的友元。但根据函数代码可以看出,函数访问了Time对象的各个成员,但是始终将ostream对象作为一个整体使用。因此它必须是Time类的友元。
函数返回一个指向ostream对象的引用,即返回一个指向调用对象(cout)的引用,因此可以像下面一样使用。
int x = 5; int y = 6; cout << x << y;
Time类:
#pragma once #include <iostream> class Time { private: int hours; int minutes; public: Time(); Time(int h, int m); void AddMin(int m); void AddHr(int h); void Reset(int h = 0, int m = 0); Time operator+(const Time &t) const; Time operator-(const Time &t) const; Time operator*(double n) const; friend Time operator*(double n, const Time& t); friend std::ostream & operator<<(std::ostream& os, const Time &t); void Show() const; };
函数定义:
#include "Time.h" #include <iostream> Time::Time() { hours = 0; minutes = 0; } Time::Time(int h, int m) { hours = h; minutes = m; } void Time::AddMin(int m) { minutes += m; while (minutes>=60) { hours++; minutes -= 60; } } void Time::AddHr(int h) { hours += h; } void Time::Reset(int h, int m) { hours = h; minutes = m; } Time Time::operator+(const Time& t) const { Time sum; sum.minutes = minutes + t.minutes; sum.hours = hours + t.hours + sum.minutes / 60; sum.minutes %= 60; return sum; } Time Time::operator-(const Time& t) const { Time diff; int tot1, tot2; tot1 = hours * 60 + minutes; tot2 = t.hours * 60 + t.minutes; diff.minutes = (tot1 - tot2) % 60; diff.hours = (tot1 - tot2) / 60; return diff; } Time Time::operator*(double n) const { Time mult; long totalminutes = hours * n * 60 + minutes * n; mult.minutes = totalminutes % 60; mult.hours = totalminutes / 60; return mult; } void Time::Show() const { std::cout << hours << "h" << minutes << "min\n"; } Time operator*(double n,const Time& t){ return t * n; } std::ostream & operator<<(std::ostream & os, const Time& t) { os << t.hours << "hours," << t.minutes << "minutes\n"; return os; }