当前位置: 首页 > news >正文

c++ primer plus 第15章友,异常和其他:友元类

c++ primer plus 第15章友,异常和其他:友元类

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:友元类


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • c++ primer plus 第15章友,异常和其他:友元类
  • 15.1 友元
    • 15.1.1 友元类
    • 程序清单 15.1 tv.h
    • 程序清单 15.2 tv.cpp
  • 总结


15.1 友元

本书前面的一些示例将友元函数用于类的扩展接口中,类并非只能拥有友元函数,也可以将类作为友元。在这种情况下,友元类的所有方法都可以访问原始类的私有成员和保护成员。另外,也可以做更严格的限制,只将特定的成员函数指定为另一个类的友元。哪些函数、成员函数或类为友元是由类定义的,而不能从外部强加友情。因此,尽管友元被授予从外部访问类的私有部分的权限,但它们并不与面向对象的编程思想相悖;相反,它们提高了公有接口的灵活性。

15.1.1 友元类

什么时候希望一个类成为另一个类的友元呢?我们来看一个例子。假定需要编写一个模拟电视机和遥控器的简单程序。决定定义一个Tv类和一个 Remote类,来分别表示电视机和遥控器。很明显,这两个类之间应当存在某种关系,但是什么样的关系呢?遥控器并非电视机,反之亦然,所以公有继承的is-a关系并不适用。遥控器也非电视机的一部分,反之亦然,因此包含或私有继承和保护继承的 has-a关系也不适用。事实上,遥控器可以改变电视机的状态,这表明应将 Romote 类作为Tv类的一个友元。首先定义Tv类。可以用一组状态成员(描述电视各个方面的变量)来表示电视机。下面是一些可能的状态:

  • 开/关;
  • 频道设置;
  • 音量设置;
  • 有线电视或天线调节模式;
  • TV 调谐或 A/V 输入。
  • 调节模式指的是,在美国,对于有线接收和 UHF 广播接收,14频道和14频道以上的频道间隔是不同的。输入选择包括TV(有线TV或广播TV)和 DVD。有些电视机可能提供更多的选择,如多种 DVD/蓝光输入,但对于这个示例的目的而言,这个清单足够了。

另外,电视机还有一些不是状态变量的参数。例如,可接收频道数随电视机而异,可以包括一个记录

这个值的成员。接下来,必须给类提供一些修改这些设置的方法。当前,很多电视机都将控件藏在面板后面,但大多数电视机还是可以在不使用遥控器的情况下进行换台等工作的,通常只能逐频道换台,而不能随意选台。同样,通常还有两个按钮,分别用来增加和降低音量。
遥控器的控制能力应与电视机内置的控制功能相同,它的很多方法都可通过使用Tv方法来实现。另外,遥控器通常都提供随意选择频道的功能,即可以直接从2频道换到20频道,并不用逐次切换频道。另很多遥控器都有多种工作模式,如用作电视控制器和 DVD遥控器。外,这些考虑因素表明,定义应类似于程序清单 15.1。定义中包括一些被定义为枚举的常数。下面的语句使 Remote 成为友元类:
friend class Remote;友元声明可以位于公有、私有或保护部分,其所在的位置无关紧要。由于Remote类提到了Tv类,所以编译器必须了解 Tv 类后,才能处理 Remote 类,为此,最简单的方法是首先定义 Tv类。也可以使用前向声明(forward delaration),这将稍后介绍。

程序清单 15.1 tv.h

// tv.h -- Tv and Remote classes
#ifndef TV_H_
#define TV_H_class Tv
{
public:friend class Remote;   // Remote can access Tv private partsenum {Off, On};enum {MinVal,MaxVal = 20};enum {Antenna, Cable};enum {TV, DVD};Tv(int s = Off, int mc = 125) : state(s), volume(5),maxchannel(mc), channel(2), mode(Cable), input(TV) {}void onoff() {state = (state == On)? Off : On;}bool ison() const {return state == On;}bool volup();bool voldown();void chanup();void chandown();void set_mode() {mode = (mode == Antenna)? Cable : Antenna;}void set_input() {input = (input == TV)? DVD : TV;}void settings() const; // display all settings
private:int state;             // on or offint volume;            // assumed to be digitizedint maxchannel;        // maximum number of channelsint channel;           // current channel settingint mode;              // broadcast or cableint input;             // TV or DVD
};class Remote
{
private:int mode;              // controls TV or DVD
public:Remote(int m = Tv::TV) : mode(m) {}bool volup(Tv & t) { return t.volup();}bool voldown(Tv & t) { return t.voldown();}void onoff(Tv & t) { t.onoff(); }void chanup(Tv & t) {t.chanup();}void chandown(Tv & t) {t.chandown();}void set_chan(Tv & t, int c) {t.channel = c;}void set_mode(Tv & t) {t.set_mode();}void set_input(Tv & t) {t.set_input();}
};
#endif

在程序清单15.1中,大多数类方法都被定义为内联的。除构造函数外,所有的Romote方法都将一个Tv 对象引用作为参数,这表明遥控器必须针对特定的电视机。程序清单15.2列出了其余的定义。音量设置函数将音量成员增减一个单位,除非声音到达最大或最小。频道选择函数使用循环方式,最低的频道设置为1,它位于最高的频道设置maxchannel之后。
很多方法都使用条件运算符在两种状态之间切换:

void onoff(){state=(state ==On)? ff :On;

如果两种状态值分别为tnue(1)和false(0),则可以结合使用将在附录E讨论的按位异或和赋值运算符(^=)来简化上述代码:

void onoff()state^=1;

程序清单 15.2 tv.cpp

// tv.cpp -- methods for the Tv class (Remote methods are inline)
#include <iostream>
#include "tv.h"bool Tv::volup()
{if (volume < MaxVal){volume++;return true;}elsereturn false;
}
bool Tv::voldown()
{if (volume > MinVal){volume--;return true;}elsereturn false;
}void Tv::chanup()
{if (channel < maxchannel)channel++;elsechannel = 1;
}void Tv::chandown()
{if (channel > 1)channel--;elsechannel = maxchannel;
}void Tv::settings() const
{using std::cout;using std::endl;cout << "TV is " << (state == Off? "Off" : "On") << endl;if (state == On){cout << "Volume setting = " << volume << endl;cout << "Channel setting = " << channel << endl;cout << "Mode = "<< (mode == Antenna? "antenna" : "cable") << endl;cout << "Input = "<< (input == TV? "TV" : "DVD") << endl;}
}

程序清单 15.3是一个简短的程序,可以测试一些特性。另外,可使用同一个遥控器控制两台不同的电视机。

//use_tv.cpp -- using the Tv and Remote classes
#include <iostream>
#include "tv.h"int main()
{using std::cout;Tv s42;cout << "Initial settings for 42\" TV:\n";s42.settings();s42.onoff();s42.chanup();cout << "\nAdjusted settings for 42\" TV:\n";s42.settings();Remote grey;grey.set_chan(s42, 10);grey.volup(s42);grey.volup(s42);cout << "\n42\" settings after using remote:\n";s42.settings();Tv s58(Tv::On);s58.set_mode();grey.set_chan(s58,28);cout << "\n58\" settings:\n";s58.settings();// std::cin.get();return 0; 
}

下面是程序清单15.1~程序清单15.3组成的程序的输出:
在这里插入图片描述

总结

这个练习的主要目的在于表明,类友元是一种自然用语,用于表示一些关系。如果不使用某些形式的友元关系,则必须将Tv类的私有部分设置为公有的,或者创建一个笨拙的、大型类来包含电视机和遥控器。这种解决方法无法反应这样的事实,即同一个遥控器可用于多台电视机。

相关文章:

c++ primer plus 第15章友,异常和其他:友元类

c primer plus 第15章友&#xff0c;异常和其他&#xff1a;友元类 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;友元类 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的…...

面试题002-Java-Java集合

面试题002-Java-Java集合 目录 面试题002-Java-Java集合题目自测题目答案1. 说说 List,Set,Map 三者的区别&#xff1f;三者底层的数据结构&#xff1f;2. 有哪些集合是线程不安全的&#xff1f;怎么解决呢&#xff1f;3. 比较 HashSet 、LinkedHashSet 和 TreeSet 三者的异同&…...

数组越界情况

数组越界情况...

工作日常学习记录

使用情景 今天开发上遇到一个搜索的需求&#xff0c;要求可以多选&#xff0c;模糊查询。我首先和前端沟通&#xff0c;前端多选后使用逗号分隔&#xff0c;拼成字符串传输给我&#xff0c;我后端再进行具体的处理。 具体处理 初步构想 由于需要查询的字段也是一个长的字符…...

C#中的容器

1、数组 数组是存储相同类型元素的固定大小的顺序集合 声明数组时&#xff0c;必须指定数组的大小 2.数组的插入和删除数据比较麻烦&#xff0c;但是查询比较快 2、动态数组&#xff08;ArrayList&#xff09; 动态数组&#xff1a;可自动调节数组的大小 可以存储任意类型数…...

rust + mingw安装教程

0. 说明 windows上安装rust时&#xff0c;需要在电脑上安装C/C构建工具。推荐的的两种工具链可以选择&#xff1a; visual studio build toolsmingw 官方推荐使用visual studio&#xff0c;若你的电脑上已经安装了visual studio&#xff0c;则无需再安装&#xff0c;直接安装…...

【sqlite3】联系人管理系统

SQLite3实现简单的联系人管理系统 有关sqlite3的基础知识请点击&#xff1a;SQLite3的使用 效果展示&#xff1a; 创建一个名为contacts.db的数据库 首先&#xff0c;我们需要创建一个名为contacts.db的数据库&#xff0c;并建立一个名为"contact"的表&#xff0…...

秋招Java后端开发冲刺——并发篇2(JMM与锁机制)

本文对Java的内存管理模型、volatile关键字和锁机制进行详细阐述&#xff0c;包括synchronized关键字、Lock接口及其实现类ReentrantLock、AQS等的实现原理和常见方法。 一、JMM&#xff08;Java内存模型&#xff09; 1. 介绍 JMM定义了共享内存中多线程程序读写操作的行为规…...

记录一次Chrome浏览器自动排序ajax请求的JSON数据问题

文章目录 1.前言2. 为什么会这样&#xff1f;3.如何解决&#xff1f; 1.前言 作者作为新人入职的第一天&#xff0c;mentor给了一个维护公司运营平台的小需求&#xff0c;具体需求是根据运营平台的某个管理模块所展示记录的某些字段对展示记录做排序。 第一步&#xff1a; myb…...

【嵌入式——FreeRTOS】任务

【嵌入式——FreeRTOS】任务 任务创建和删除动态方式创建任务静态方式创建任务 删除任务任务切换调度器任务切换流程 任务挂起任务恢复相关API函数 任务创建和删除 动态方式创建任务 任务的任务控制块以及任务的栈空间所需的内存&#xff0c;均由freeRTOS从freeRTOS管理的堆中…...

网关,路由器,交换机

一、网关 (Gateway) 是一种设备&#xff0c;用于连接不同网络&#xff0c;能够转发数据包并翻译协议&#xff0c;允许不同类型的网络通信。网关通常工作在OSI模型的应用层或传输层&#xff0c;提供连接和路由服务。 应用场景例子&#xff1a; 在企业网络中&#xff0c;网关可…...

sublime 3 背景和字体颜色修改

sublime 4 突然抽风&#xff0c;每次打开都显示 “plugin_host-3.3 has exited unexpectedly, some plugin functionality won’t be available until Sublime Text has been restarted” 一直没调好&#xff0c;所以我退回到sublime 3了。下载好了软件没问题&#xff0c;但是一…...

leetcode 403周赛 包含所有1的最小矩形面积||「暴力」

3197. 包含所有 1 的最小矩形面积 II 题目描述&#xff1a; 给你一个二维 二进制 数组 grid。你需要找到 3 个 不重叠、面积 非零 、边在水平方向和竖直方向上的矩形&#xff0c;并且满足 grid 中所有的 1 都在这些矩形的内部。 返回这些矩形面积之和的 最小 可能值。 注意…...

Stable Diffusion web UI 插件

2024.7.3更新&#xff0c;持续更新中 如果需要在linux上自己安装sd&#xff0c;参考&#xff1a;stable diffusion linux安装 插件复制到 /stable-diffusion-webui/extensions 目录下&#xff0c;然后重新启动sd即可 一、插件安装方法 每种插件的安装方法可能略有不同&#xf…...

深度学习中的反向传播算法的原理

深度学习中的反向传播算法的原理&#xff0c;以及如何计算梯度 反向传播算法&#xff08;Backpropagation&#xff09;是深度学习中最核心的优化技术之一&#xff0c;用于训练神经网络。它基于链式法则&#xff0c;通过从输出层逆向计算误差并逐层传递到输入层来更新模型参数&…...

身处奇瑞看三星:既“开卷“又“起火“,却更难受了

三星"起火" 这几天奇瑞的事情&#xff0c;让大家破防了&#xff0c;纷纷表示国内的就业市场环境普遍恶劣。 那我们转个眼&#xff0c;看看海外企业的情况。 最近一周&#xff0c;三星频频登上新闻&#xff0c;颇有"起火"之势。 在刚步入下半年的 7 月 1 日…...

系统架构设计师教程(清华第2版)<第1章 绪论>解读

系统架构设计师教程 第一章 绪论 1.1 系统架构概述1.1.1 系统架构的定义及发展历程1.1.2 软件架构的常用分类及建模方法1.1.3 软件架构的应用场景1.1.4 软件架构的发展未来1.2 系统架构设计师概述1.2.1 架构设计师的定义、职责和任务1.2.2 架构设计师应具备的专业素质1.3 如何成…...

Vue + Element UI + JSEncrypt实现简单登录页面

安装依赖 npm install jsencrypt --save局部引入 import JSEncrypt from jsencrypt/bin/jsencrypt;登录页面index.vue <template><div class"loginbody"><div class"logindata"><div class"logintext"><h2>Wel…...

从“关注流”到“时间线”,搜狐给内容加信任价值

文 | 螳螂观察 作者 | 易不二 在近日第十六季搜狐新闻马拉松活动中&#xff0c;搜狐新闻APP的“时间线”功能备受瞩目。不仅开幕式现场竖了一块“左手时间线&#xff0c;右手关注流”的路牌&#xff0c;张朝阳也着重强调了“时间线”产品的互动方式&#xff1a;“关注是基础&…...

vscode的一些使用问题

vscode使用技巧 1、快捷键&#xff08;1&#xff09;打开命令面板&#xff08;2&#xff09;注释&#xff08;3&#xff09;删除行&#xff08;4&#xff09;上下移动光标&#xff08;5&#xff09;光标回退&#xff08;6&#xff09;复制行&#xff08;7&#xff09;插入空白行…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...