通常情况下,公有类方法是访问类对象私有部分的唯一途径。除此之外,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. Go 单元测试基本介绍

    目录 一.单元测试基本介绍 1.1 什么是单元测试? 1.2 如何写好单元测试 1.3 单元测试的优点 1.4 单元测试的设计原则 二.Go语言测试 2.1 Go单元测试概要 2.2 Go单元测试基本 ...

  2. 【Azure Developer】.Net 简单示例 "文字动图显示" Typing to SVG

    问题描述 看见一个有趣的页面,可以把输入的文字信息,直接输出SVG图片,还可以实现动图模式. 示例URL:  https://readme-typing-svg.demolab.com/?font=F ...

  3. vue项目如何部署?有遇到布署服务器后刷新404问题吗?

    一.如何部署 前后端分离开发模式下,前后端是独立布署的,前端只需要将最后的构建物上传至目标服务器的web容器指定的静态目录下即可 我们知道vue项目在构建后,是生成一系列的静态文件 常规布署我们只需要 ...

  4. C++ 构造函数实战指南:默认构造、带参数构造、拷贝构造与移动构造

    C++ 构造函数 构造函数是 C++ 中一种特殊的成员函数,当创建类对象时自动调用.它用于初始化对象的状态,例如为属性分配初始值.构造函数与类同名,且没有返回值类型. 构造函数类型 C++ 支持多种类 ...

  5. anconda配置tensorflow环境

    一.anconda的安装 1.进入Anaconda官网并按照电脑配置选择合适的安装包 Anaconda官网:https://www.anaconda.com/ 点击进入 不同的三个版本,分别是wind ...

  6. 谢老师2024春 - Day2:期望DP

    Day2:期望DP​​ A - CF148D Bag of mice 设 \(dp_{i,j}\) 表示还剩下 \(i\) 只白鼠,\(j\) 只黑鼠 A 的胜率. 大家都没有拿到白鼠,那么 B 赢, ...

  7. ModelScope初探:一行代码调用成熟AI模型

    简介: 如何用一行代码调用成熟AI模型?试试ModelScope,让AI开发者解放生产力! ModelScope是阿里推出的下一代开源的模型即服务共享平台,为泛AI开发者提供灵活.易用.低成本的一站式 ...

  8. Quick BI产品核心功能大图(五)移动端:让数据在更多业务场景中流通

    ​简介:将数据更好的融入日常工作中,一个重要的前提条件就是多端多渠道的数据触达和办公协同能力. Quick BI凭借移动端交互体验,帮助用户随时随地便捷查看报表,并通过在线协同方式,追踪策略的执行落地 ...

  9. N个技巧,编写更高效 Dockerfile|云效工程师指北

    简介:云原生时代下软件的构建和部署离不开容器技术.提到容器,几乎大家下意识都会联想到 Docker .而 Docker 中有两个非常重要的概念,一个是Image(镜像),一个是Container(容器 ...

  10. KubeVela 成为 CNCF 沙箱项目,让云端应用交付更加简单

    简介: KubeVela 就是这样一个面向用户的上层平台项目.对于业务开发者来说,KubeVela 简单.易用,它可以让开发者以极低的心智负担和上手成本在 Kubernetes 上定义与部署应用... ...