Effective C++读书笔记——item23(用非成员,非友元函数取代成员函数)

一、主要观点

  • 在某些情况下,使用 non-membernon-friend 函数来替换 member 函数可以增强封装性和可扩展性,提供更好的软件设计。

二、详细解释

  1. 封装性

    • 类成员函数的封装性考量:成员函数可以访问类的 private 成员,这在一定程度上破坏了封装性。因为它拥有比实际所需更多的对类内部的访问权限。例如,对于一个类 Widget 的成员函数,它可以访问类的所有 private 数据成员和函数,即使某些数据或函数并不需要被该成员函数操作。
    • non-member、non-friend 函数的优势non-membernon-friend 函数只能通过类的 public 接口来访问类,这意味着它们不能直接访问类的 private 成员。这种方式可以将类的内部实现细节更好地隐藏起来,增强封装性。例如,对于一个处理 Widget 类对象的 non-membernon-friend 函数,它只能通过 Widget 类的 public 接口进行操作,不能访问 Widget 类内部的 private 成员,这样类的内部实现可以更加自由地修改而不影响这个外部函数。
  2. 可扩展性

    • 对类功能的扩展更灵活使用 non-membernon-friend 函数可以将不同的功能分布在不同的函数中,而不是将所有功能都集中在类的成员函数里。这样,当需要对类的功能进行扩展时,可以方便地添加新的 non-membernon-friend 函数,而不需要修改类的内部实现。
    • 命名空间的使用可以将相关的 non-membernon-friend 函数放在一个命名空间中,形成一个功能集合。这样可以更好地组织代码,并且可以根据不同的功能模块将函数分类到不同的命名空间中,方便代码的管理和维护。例如:
     
    namespace WidgetStuff {class Widget {... };void doSomething(Widget& w);void doAnotherThing(Widget& w);
    }
    
     

    这里,doSomething 和 doAnotherThing 是 non-membernon-friend 函数,它们通过 Widget 的 public 接口操作 Widget 类,当需要添加新的操作 Widget 的函数时,只需在 WidgetStuff 命名空间中添加即可,而不用修改 Widget 类。

  3. 编译依赖关系

    • 减少依赖member 函数的修改通常会导致类的重新编译,因为它是类定义的一部分。而 non-membernon-friend 函数的修改通常只需要重新编译该函数本身,减少了对类的依赖。这在大型项目中可以提高编译速度。
    • 降低耦合non-membernon-friend 函数与类的耦合度相对较低,使得类的接口更加稳定,避免因修改函数而影响类的内部实现和其他使用该类的代码。
  4. 示例说明

    • 考虑一个表示网页浏览器的类 WebBrowser,可能有清除缓存、清除历史记录、清除 Cookies 等操作。可以有两种实现方式:
     
    class WebBrowser {
    public:void clearCache();void clearHistory();void clearCookies();void clearEverything() {  // member functionclearCache();clearHistory();clearCookies();}
    };
    
     

    或者使用 non-membernon-friend 函数:

    class WebBrowser {
    public:void clearCache();void clearHistory();void clearCookies();
    };void clearEverything(WebBrowser& wb) {  // non-member, non-friend functionwb.clearCache();wb.clearHistory();wb.clearCookies();
    }
    
     

    在这个例子中,使用 non-membernon-friend 函数 clearEverything 可以将清除操作的功能与 WebBrowser 类分离,避免 WebBrowser 类变得臃肿,同时也不会增加 WebBrowser 类的封装性负担,因为 clearEverything 函数无法访问 WebBrowser 类的 private 成员。

三、总结

  • 为了实现更好的封装性、可扩展性、降低编译依赖和降低耦合度,在某些情况下,应该优先考虑使用 non-membernon-friend 函数而不是 member 函数。这有助于将类的功能分离,提高代码的可维护性和组织性,同时使类的内部实现更加独立和灵活。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/67894.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三相电变为家庭220V,市电火线和零线关系,为什么用三相电输送

参考: https://www.zhihu.com/question/30555841/answer/85723024 上面是电力系统的主要组成,发电站发电后升压传输,然后到各大城市再降压使用。 我们看到电塔上都是三根线,那么因为整个过程都是三相电。 为什么用三相电&#xff…

Python----Python高级(正则表达式:语法规则,re库)

一、正则表达式 1.1、概念 正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex、 regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母&#xff0…

linux网络 | 传输层TCP | 认识tcp报头字段与分离

前言: 本节内容继续传输层的讲解, 本节讲解的是tcp协议。 tcp协议是我们日常中最常用的协议。就比如我们浏览网页,我们知道网页时http或者https协议。 其实http或者https底层就是用的tcp协议。tcp协议,全名又称为传输控制协议&…

Mysql触发器(学习自用)

一、介绍 二、触发器语法 注意:拿取新的数据时用new,旧数据用old。

ubuntu20使用apt安装mysql8

目录 ubuntu20使用apt安装mysql8报错列表参考链接首先删除旧mysql 一、下载配置mysql8库索引下载apt包解压包配置更新apt库索引 二、下载安装mysql8三、启动mysql服务配置开机自启动,忽略 本地登录远程登录查看mysql的所有用户使用客户端远程登陆如果报错完成 参考链…

昇腾AI产品

一.AI计算的基础知识 1.并行计算 指同时使用多种计算资源解决技术问题的过程,是提高计算机系统计算速度和数据处理能力的一种有效手段。它的基本思想是用多个处理器来共同求解同一个问题,即将被求解的问题分解成若干个部分,各部分均由一个独…

Linux内核编程(二十一)USB驱动开发-键盘驱动

一、驱动类型 USB 驱动开发主要分为两种:主机侧的驱动程序和设备侧的驱动程序。一般我们编写的都是主机侧的USB驱动程序。 主机侧驱动程序用于控制插入到主机中的 USB 设备,而设备侧驱动程序则负责控制 USB 设备如何与主机通信。由于设备侧驱动程序通常与…

学习Hibernate的调优方案

Hibernate是一个非常流行的Java ORM(对象关系映射)框架,它可以帮助开发者更轻松地处理数据库操作。然而,如果不进行适当的性能调优,Hibernate可能会导致应用程序运行缓慢。本文将详细探讨Hibernate的调优方案&#xff…

总结 uniapp 上不适配iphone的:new Date 时间、border线条、渐变

1、border样式缺了一边 这是错误样式: 需要添加: border: 1rpx solid #57c7bb; transform: rotateZ(0deg);//加入此代码解决iphone 不适配问题2、时间出现NaN 原因是因为ios中使用new Date 的时候出了问题 解决方案: 1.调整时间格式:将时间格式从"yyyy-MM-d…

内网渗透测试工具及渗透测试安全审计方法总结

1. 内网安全检查/渗透介绍 1.1 攻击思路 有2种思路: 攻击外网服务器,获取外网服务器的权限,接着利用入侵成功的外网服务器作为跳板,攻击内网其他服务器,最后获得敏感数据,并将数据传递到攻击者&#xff0…

Dockerfile另一种使用普通用户启动的方式

基础镜像的Dockerfile # 使用 Debian 11.9 的最小化版本作为基础镜像 FROM debian:11.11# 维护者信息 LABEL maintainer"caibingsen" # 复制自定义的 sources.list 文件(如果有的话) COPY sources.list /etc/apt/sources.list # 创建…

力扣707题——设计链表

#题目 从零开始设计链表,我们拆分成两次任务,今天先看1 ,2 ,4 #代码

leetcode刷题记录(七十二)——146. LRU 缓存

(一)问题描述 146. LRU 缓存 - 力扣(LeetCode)146. LRU 缓存 - 请你设计并实现一个满足 LRU (最近最少使用) 缓存 [https://baike.baidu.com/item/LRU] 约束的数据结构。实现 LRUCache 类: * LRUCache(int capacity)…

微信小程序:实现单选,多选,通过变量控制单选/多选

一、实现单选功能 微信小程序提供了 radio 组件来实现单选功能。radio 组件需要配合 radio-group 使用。 1. WXML 代码 <radio-group bindchange"onRadioChange"><label wx:for"{{items}}" wx:key"id"><radio value"{{it…

vue2使用flv.js在浏览器打开flv格式视频

组件地址&#xff1a;GitHub - bilibili/flv.js: HTML5 FLV Player flv.js 仅支持 H.264 和 AAC/MP3 编码的 FLV 文件。如果视频文件使用了其他编码格式就打不开。 flv.vue <template><div><el-dialog :visible.sync"innerVisibleFlv" :close-on-pre…

Spring 中的事件驱动模型

事件驱动的基本了解 事件模式也就是观察者模式&#xff0c;当一个对象改变的时候&#xff0c;所有依赖的对象都会收到一个通知。 Subject&#xff1a;抽象主题 Observer&#xff1a;具体主题 Concrete Subject&#xff1a;抽象观察者&#xff0c;在得到更新通知之后去更新自…

STM32补充——IAP

0 前置知识&#xff1a; FLASH相关内容&#xff1a;前往STM32补充——FLASH STM32三种烧录方式&#xff08;看看就行&#xff09;&#xff1a; 1.ISP&#xff1a;In System Programming&#xff08;在系统编程&#xff09; 执行芯片厂商的 Bootloader 程序进入 ISP 模式&…

k8s的CICD实施项目

环境需求&#xff1a; 目前领导需要做一个需求&#xff0c;临时把我从运维岗位&#xff0c;把我调度到到专家组让我主导cicd的项目实施 目前环境资源 k8s环境&#xff0c;28台服务器&#xff0c;上面是k8s集群&#xff0c;要实施一个测试环境的cicd以及一个生产环境的cicd gitl…

【线性代数】基础版本的高斯消元法

[精确算法] 高斯消元法求线性方程组 线性方程组 考虑线性方程组&#xff0c; 已知 A ∈ R n , n , b ∈ R n A\in \mathbb{R}^{n,n},b\in \mathbb{R}^n A∈Rn,n,b∈Rn&#xff0c; 求未知 x ∈ R n x\in \mathbb{R}^n x∈Rn A 1 , 1 x 1 A 1 , 2 x 2 ⋯ A 1 , n x n b 1…

AIGC视频生成模型:Runway的Gen系列模型

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍Runway开发的视频生成模型Gen系列&#xff0c;包括Gen-1、Gen-2和Gen3 Alpha等&#xff0c;这些模型每次发布都震惊AI圈&#xff0c;荣获多个视频生成的…