通常情况下,公有类方法是访问类对象私有部分的唯一途径。除此之外,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;
}

C++笔记(4)友元的更多相关文章

  1. C++学习笔记之友元

    一.引言 C++控制对类对象私有部分(private)的访问,通常只能通过公有的(public)类方法去访问.但是有时候这种限制太严格,不适合特定的问题,于是C++提供了另外一种形式的访问权限:友元. ...

  2. 【C/C++笔记】友元类函数

    最近学了友元,有三个用法: 1友元函数 2友元类 3友元类函数 我发现友元类函数的用法要比上两个用法要严格,不按格式写会各种出错,要把两个类都拆开来写,共分4步. 第一步: class A; //有 ...

  3. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_友元程序集

    [应用场景] 程序集A访问程序集B定义的Internal访问类型的类的成员. [使用方式] 在构建程序集B的时候,引入System.Runtime.CompilerServices,以此来添加Inte ...

  4. 初探C++运算符重载学习笔记&lt;2&gt; 重载为友元函数

    初探C++运算符重载学习笔记 在上面那篇博客中,写了将运算符重载为普通函数或类的成员函数这两种情况. 以下的两种情况发生.则我们须要将运算符重载为类的友元函数 <1>成员函数不能满足要求 ...

  5. C++学习笔记 构造&析构 友元 new&delete

    构造&析构函数 构造函数 定义:与类同名,可以有参可以无参,主要功能用于在类的对象创建时定义初始化的状态,无返回值,也不能用void修饰,构造函数不能被直接调用,必须通过new运算符在创建对象 ...

  6. C++学习笔记(十六):友元

    问题的提出: 我们已知道类具备封装和信息隐 藏的特性.只有类的成员函数才能访问类的私有成员,程式中的其他函数是无法访问私有成员的.非成员函数能够访问类中的公有成员,但是假如将数据成员都定义 为公有的, ...

  7. C++ Primer 学习笔记_53_类和数据抽象 --友元、static员

    分类 --友元.static成员 一.友元 友元机制同意一个类将对其.友元关系:一个样例 如果一个窗体管理类Window_Mgr可能须要訪问由其管理的Screen对象的内部数据.Screen应该同意其 ...

  8. 读书笔记 effective c++ Item 23 宁可使用非成员非友元函数函数也不使用成员函数

    1. 非成员非友元好还是成员函数好? 想象一个表示web浏览器的类.这样一个类提供了清除下载缓存,清除URL访问历史,从系统中移除所有cookies等接口: class WebBrowser { pu ...

  9. 《C++ Primer Plus》第15章 友元、异常和其他 学习笔记

    友元使得能够为类开发更灵活的接口.类可以将其他函数.其他类和其他类的成员函数作为友元.在某些情况下,可能需要前向声明,需要特别注意类和方法声明的顺序,以正确地组合友元.潜逃类是在其他类中生命的类,它有 ...

  10. 《C++ Primer Plus》15.1 友元 学习笔记

    15.1.1 友元类假定需要编写一个模拟电视机和遥控器的简单程序.决定定义一个Tv类和一个Remote类,来分别表示电视机和遥控器.遥控器和电视机之间既不是is-a关系也不是has-a关系.事实上,遥 ...

随机推荐

  1. 并发系列64章(TPL 数据流(二))第八章

    前言 续第七章. 正文 数据流块的并行处理 数据流块在网格上本身就是并行的,为什么这么说呢? 加入有两个数据库,他们链接在一起,然后给他们post数据. 当数据流块一在运行的时候,数据流块二也在执行, ...

  2. szfpga Lattice高速下载器HW-USBN-2B 常见问题解答

    .产品特点 1). 支持windows7,Windows10 操作系统,两个操作系统非常稳定不断线. 2). 支持JTAG 模式,速度快,最高30Mb/s,调试serdes core,不会像hw-us ...

  3. NOIP模拟四

    NOIP模拟四 number 题目描述 现有 \(2^n\) 个点,点编号为 \(0\sim2^n-1\). 定义这些点的一张异或图为: 先选定一个集合 \(S\). 对于原图上编号为 \(x\) 和 ...

  4. 开源数据库PolarDB为什么能捕获娃哈哈的心?

    简介: 在10月25日由阿里云开发者社区.PolarDB开源社区.infoQ联合举办的「开源人说」第三期--<数据库PolarDB专场>沙龙上,中启乘数科技(杭州)有限公司联合创始人唐成带 ...

  5. 迁移 Express 到函数计算

    首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算准备计 ...

  6. 小米电商 Apache Dubbo-go 微服务实践

    ​简介:2021 年是小米中国区电商部门变动调整较大的一年,小米中国区早期电商.服务体系建立在 Go 语言构建的微服务体系之上,由内部自研的 Go 语言微服务框架 koala 支撑起数以千计的微服务应 ...

  7. hyengine - 面向移动端的高性能通用编译/解释引擎

    ​简介:手机淘宝客户端在历史上接过多种多样的脚本引擎,用于支持的语言包括:js/python/wasm/lua,其中js引擎接过的就有:javascriptcore/duktape/v8/quickj ...

  8. dotnet 是否应该对 HttpResponseMessage 调用 Dispose 进行释放

    对于 HttpClient 的请求响应值 HttpResponseMessage 来说,既然继承了 IDisposable 接口,自然就是想让大家可以通过 using 或者手动调用 Dispose 进 ...

  9. 3种方式自动化控制APP

    自动化控制APP不管是在工作还是生活方面,都可以帮助我们高效地完成任务,节省时间和精力.本文主要介绍自动化控制APP的3种常用方式. 1.Python + adb 这种方式需要对Android有一些基 ...

  10. Gradle8.4构建SpringBoot多模块项目

    Gradle8.4构建SpringBoot多模块项目 一.基本 1.版本 这个版本是Jdk8最后一个SpringBoot版本 软件 版本 Gradle 8.4 SpringBoot 2.7.15 JD ...