[翻译] Effective C++, 3rd Edition, Item 23: 用 non-member non-friend functions(非成员非友元函数)取代 member functions(成员函数)

信号处理中的滤波器的阶数和谐波的理解 最近在读paper的时候,遇到了一些以前遗忘的问题,先重新查找,记录在这里,以备不时之查看。 我相信一定有小伙伴跟我有过一样的疑惑,那就是我们在使用滤波器的时候,总是遇到滤波器的阶数这个概念参数,我们很多都是根据别的paper里的设置,设置自己的科研参数,其实并不是很理解其中的含义: 其实我们常用的阶数N的意思是: 滤波器的阶数,就是指过滤谐波的次数,一般来讲,同样的滤波器,其阶 阅读详情

Item 23: 用 non-member non-friend functions(非成员非友元函数)取代 member functions(成员函数)

作者:Scott Meyers

译者:fatalerror99 (iTePub's Nirvana)

发布:http://blog.youkuaiyun.com/fatalerror99/

想象一个代表 web browsers(网页浏览器)的 class。在这样一个 class 可能提供的大量函数中包括清空已下载部分的缓存,清空已访问 URLs 的历史,以及从系统移除所有 cookies 的功能:

class WebBrowser {
public:
  ...
  void clearCache();
  void clearHistory();
  void removeCookies();
  ...
};

很多用户希望能一起执行全部这些动作,所以 WebBrowser 可能也会提供一个函数去这样做:

class WebBrowser {
public:
  ...
  void clearEverything();               // calls clearCache, clearHistory,
                                        // and removeCookies
  ...
};

当然,这个功能也能通过用一个 non-member function(非成员函数)调用适当的 member functions(成员函数)来提供:

void clearBrowser(WebBrowser& wb)
{
  wb.clearCache();
  wb.clearHistory();
  wb.removeCookies();
}

那么哪个更好呢,member function(成员函数)clearEverything 还是 non-member function(非成员函数)clearBrowser?

object-oriented(面向对象)原则指出:数据和对它们进行操作的函数应该被绑定到一起,而且建议 member function(成员函数)是更好的选择。不幸的是,这个建议是不正确的。它产生于对 object-oriented(面向对象)是什么的一个误解。object-oriented(面向对象)原则指出数据应该尽可能 encapsulated(被封装)。与直觉不同,member function(成员函数)clearEverything 居然会造成比 non-member function(非成员函数) clearBrowser 更弱的 encapsulation(封装)。此外,non-member function(非成员函数)为 WebBrowser 相关功能提供了更大的包装机动性,而且,可以获得更少的 compilation dependencies(编译依赖)和 WebBrowser 可扩展性的增强。因而,因此在很多方面 non-member(非成员)的方法比一个 member function(成员函数)更好。理解它的原因是非常重要的。

我们将从 encapsulation(封装)开始。如果某物被封装,它被从视线中隐藏。某物被封装得越强,就越少有东西能看见它。越少有东西能看见它,我们改变它的机动性就越大,因为我们的改变仅仅直接影响那些能看见我们变了什么的东西。那么,某物被封装得越强,我们改变它的能力就越强。这就我们首先重视 encapsulation(封装)的原因:它为我们提供一种用仅仅影响有限的客户的方法改变事情的机动性。

考虑组成一个 object 的数据。越少有代码能看到数据(也就是说,访问它),数据被封装得就越强,我们改变 object 的数据的特性的自由也就越大,比如,data members(数据成员)的数量,它们的类型,等等。作为度量多少代码能看到一片数据的粗略的尺度,我们可以计数能访问那片数据的函数的数量:越多函数能访问它,数据的被封装得越弱。

Item 22 说明了 data members(数据成员)应该是 private(私有)的,因为如果它们不是,就有无限量的函数能访问它们。它们根本就没有 encapsulation(封装)。对于 private(私有)的 data members(数据成员),能访问他们的函数的数量就是 class 的 member functions(成员函数)的数量加上 friend functions(友元函数)的数量,因为只有 members(成员)和 friends(友元)才能访问 private members(私有成员)。假设在一个 member function(成员函数)(能访问的不只是一个 class 的 private data(私有数据),还有 private functions(私有函数),enums(枚举),typedefs,等等)和一个提供同样功能的 non-member non-friend function(非成员非友元函数)(不能访问上述那些东西)之间有一个选择,能导致更强 encapsulation(封装)的选择是 non-member non-friend function(非成员非友元函数),因为它不会增加能访问 class 的 private part(私有构件)的函数的数量。这就解释了为什么 clearBrowser(non-member non-friend function(非成员非友元函数))比 clearEverything(member function(成员函数))更可取:它能导致 WebBrowser class 内更强的封装。

在这一点上,有两件事值得注意。首先,这个论证只适用于 non-member non-friend functions(非成员非友元函数)。friends(友元)能像 member functions(成员函数)一样访问一个 class 的 private members(私有成员),因此同样影响 encapsulation(封装)。从 encapsulation(封装)的观点看,选择不是在 member(成员)和 non-member functions(非成员函数)之间,而是在 member functions(成员函数)和non-member non-friend functions(非成员非友元函数)之间。(当然,encapsulation(封装)并不是仅有的观点,Item 24 说明如果观点来自 implicit type conversions(隐式类型转换),选择就是在 member(成员)和 non-member functions(非成员函数)之间。)

第二件事需要注意正因为关系到 encapsulation(封装),它指出,一个函数是一个 class 的 non-member(非成员)并不意味着它不可以是另一个 class 的 member(成员)。这对于习惯了所有函数必须在 classes 中的语言(例如,Eiffel,Java,C#,等等)的程序员是一个适度的安慰。例如,我们可以使 clearBrowser 成为某些 utility class 的 static member function(静态成员函数)。只要它不是 WebBrowser 的一部分(或一个 friend(友元)),它就不会影响 WebBrowser 的 private members(私有成员)的 encapsulation(封装)。

在 C++ 中,一个更自然的方法是使 clearBrowser 成为与 WebBrowser 在同一个 namespace(名字空间)中的 non-member function(非成员函数):

namespace WebBrowserStuff {

 class WebBrowser { ... };

 void clearBrowser(WebBrowser& wb);

  ...
}

然而,相对于形式上的自然,这样更适用于它,因为 namespaces名字空间,与 classes 不同,能展开到多个源文件中。这是很重要的,因为类似 clearBrowser 的函数是 convenience functions(便利函数)。既不是 members(成员)也不是 friends(友元),它们没有对 WebBrowser 进行专门的访问,所以他们不能提供任何一种 WebBrowser 的客户不能通过其它方法获得的功能。例如,如果 clearBrowser 不存在,客户可以直接调用 clearCache,clearHistory 和 removeCookies 本身。

一个类似 WebBrowser 的 class 可以有大量的 convenience functions(便利函数),一些是书签相关的,另一些打印相关的,还有一些是 cookie 管理相关的,等等。作为一个一般的规则,多数客户仅对这些 convenience functions(便利函数)集中的一部分感兴趣。没有理由让一个只对书签相关的 convenience functions(便利函数)感兴趣的客户在编译时依赖其它函数,例如,cookie 相关的 convenience functions(便利函数)。分隔它们的直截了当的方法就是在一个头文件中声明书签相关的 convenience functions(便利函数),在另一个不同的头文件中声明 cookie 相关的 convenience functions(便利函数),在第三个头文件声明打印相关的 convenience functions(便利函数),等等:

// header "webbrowser.h" — header for class WebBrowser itself
// as well as "core" WebBrowser-related functionality
namespace WebBrowserStuff {

   class WebBrowser { ... };

     ...                                // "core" related functionality, e.g.
                                        // non-member functions almost
                                        // all clients need
}
// header "webbrowserbookmarks.h"
namespace WebBrowserStuff {
  ...                                   // bookmark-related convenience
}                                       // functions
// header "webbrowsercookies.h"
namespace WebBrowserStuff {
  ...                                   // cookie-related convenience
}                                       // functions

...

注意这就是标准 C++ 库的严密的组织方式。存在有许多头文件中(例如,<vector>,<algorithm>,<memory>,等等),每一个都声明了 std 中的一些机能,这胜于在一个单独的一体式的 <C++StandardLibrary> 头文件包含 std namespace 中的所有东西。只需要 vector 相关机能的客户不需要 #include <memory>,不用 list 的客户没有必要 #include <list>。这就允许客户在编译时只依赖于他们实际使用的系统构件。(参见 Item 31 对减少 compilation dependencies(编译依赖)的其它方法的讨论。)当机能来自一个 class 的 member functions(成员函数)时,用这种方法分割它是不可能的,因为一个 class 必须作为一个整体来定义,它不能四分五裂。

将所有 convenience functions(便利函数)放入多个头文件中——但是在一个 namespace(名字空间)中——也意味着客户能容易地扩充 convenience functions(便利函数)集。他们全部要做的就是在这个 namespace(名字空间)中加入更多的 non-member non-friend functions(非成员非友元函数)。例如,如果一个 WebBrowser 的客户决定写一个与下载图像相关的 convenience functions(便利函数),他或她仅仅需要新建一个包含那些函数在 WebBrowserStuff namespace(名字空间)中的 declarations(声明)的头文件。这个新的函数现在就像其它 convenience functions(便利函数)一样可用并被集成。这是 classes 不能提供的又一个特性,因为 class definitions(类定义)是关闭了客户扩充的。当然,客户可以派生新 classes,但是 derived classes(派生类)不能访问 base class(基类)中被封装的(也就是 private(私有)的)members(成员),所以这样的 "extended functionality"(“扩充机能”)只有二等身份。此外,就像 Item 7 中解释的,不是所有的 classes 都是作为 base classes(基类)设计的。

Things to Remember

  • 用 non-member non-friend functions(非成员非友元函数)取代 member functions(成员函数)。这样做可以提高 encapsulation(封装性),packaging flexibility(包装机动性)和 functional extensibility(机能扩展性)。
【Boost5】Boost变换器的输入电容 节点的电流有3个,一个是来自电源输入的,由于我们把Vin看成理想电源以及线路的电感的存在,它可以近似看作是恒定的电流源Iin,一个是流向输入电容Cin的电流Icin,另外一个节点是电感L电流IL。电容电流波形在整个开关周期内的平均值为0,充电和放电在一个周期中各占1/2,在图中充电部分面积和放电部分面积相等,那么在充电或放电的电荷量Q=I*t,从图中可以看出,在一个周期内电容电流变化量是ΔIL,那在电容在充电1/2T周期中电流的变化量是1/2ΔIL。输入电容上的ESR也会随着电流变化,影响输入电压的变化。 阅读详情

相关推荐

C++ bitset总结

数据结构bitset 术语:某1位置位是置1,某一位复位是某一位清零。 文章目录数据结构bitset一、3种初始化方式二、位访问三、位操作四、 位集操作总结实战练习 一、3种初始化方式 bitset<32> tmp; //默认构造函数,默认全0。 bitset<32> tmp(-1); //从整形数构造 bitset<32> tmp("101"); //从包含1和0的字符串构造 二、位访问 bitset<32> tmp(256)

qq_43807092的博客 721

Effective C++条款23——宁以non-member、non-friend替换member函数(设计与声明)

如果要你在一个member函数(它不只可以访问class内的private数据,也可以取用private函数、enums、 typedefs等等)和一一个non-member,non-friend函数(它无法访问.上述任何东西)之间做抉择,而且两者提供相同机能,那么,导致较大封装性的是non-member non-friend函数,因为它并不增加“能够访问class内之private成分”的函数数量。面向对象守则要求,数据以及操作数据的那些函数应该被捆绑在一块,这意味它建议member函数是较好的选择。

StudyWinter的博客 579

AIR780E二次开发点灯(LuatOS)

Air780E的LuatOS点灯教程,二次开发教程,可用于所有ec618平台,无需SDK

rootuseres的博客 1万+

在模板内部定义非成员函数(Define non-member functions inside templates)

《Thinking in C++》习题16.18,我的实现代码为: //: C12:IostreamOperatorOverloading.cpp // Example of non-member overloaded operators #include "../require.h" #include #include // "String streams" #include using

lichengyu的专栏 1041

UG/NX二次开发实例流程样例(nx1980+vs2019)

以上就是基本操作了,下面进入界面开发流程,nx1980的界面开发操作,也需要在块UI界面编辑器中操作,很多教程都没有讲解这一点,尤其是如何进入块UI界面编辑器,那么我在这里详细说明一下步骤。》,这一篇文章我们将详细讲述,如何开发一个具体的功能——根据用户输入的数据,在特定的点上创建一个指定大小的立方体。可以将文件保存当桌面,笔者保存在桌面的create_block目录中了,如下图所示,可以发现生成了三个文件。4.在新建模型完成后,我们准备创建交互UI,按照下图所示的顺序,找到块UI界面编辑器,。

秋月的私语 1万+

计算机考研复试面试常问问题 数据结构篇(下)

计算机考研复试面试常问问题 数据结构篇(下) 使用前需知(拒绝白嫖,如果对你有帮助,你只需点个赞就行): 注意:有人在闲鱼上盗卖我的资料,而且还有很多同学买了,请各位擦亮双眼,我是整理出来免费分享给大家的! 大家请多点赞和评论,这样后面的同学更容易百度到,不至于被人盗卖,我就不加水印影响大家使用了! 第一次整理,度不好控制,有不好的地方希望大家理解,后面可能会改进,造福今年之后的同学们! ...

程序员宝藏的博客 1万+

23 24 什么时候用non-member函数替代member函数

23 宁以 non-member、non-friend 替换member函数,可增加封装性、包裹弹性和机能扩充性 non-member non-friend 函数相对于member和friend函数而言,具有更大的封装性,因为它不能够访问class内之private成分。 non-member 可以是另一个class 的member,如工具类。 C++中比较自然的做法是让non-member成为与class同一命名空间中的non-member函数,常称为便利函数。 当某个class拥有大量的便利函数时,可

gb173652770的专栏 660

避坑指南:WSL2网络模式修改导致无法上网的解决方案(附备份还原技巧)

本文深入解析WSL2默认网络隔离机制,并提供三种安全的端口互通方案,重点推荐通过配置Windows防火墙规则实现稳定访问。同时,针对网络配置修改可能引发的无法上网问题,给出了从重置配置到系统级备份的完整恢复指南,确保开发环境安全可靠。

jj890的博客 781

Effective_C++:19、区分member functions、non-member functions和friend functions三者

19、区分member functions、non-member functions和friend functions三者 1、member functions、non-member functions和friend functions 成员函数:class的成员函数,可以是普通函数、虚函数,可以访问类的public、protected、private成员,会被派生类继承。重载运算符时参数数量...

l1dian11的博客 1594

SIMetrix教程-001.SIMetrix软件简介与安装

  由于某些原因需要用到SIMetrix仿真软件,然而网上的资料并不是特别多,故在此记录一下这款仿真软件的学习过程,也给有需要的人提供一些参考,免走弯路。如果使用过Pspice或者LTspice软件,学习SIMetrix会很容易入门,仿真软件都是大同小异的,会一样后都可以快速入门其他软件。   SIMetrix是一款以SPICE模型为基础的仿真软件,集成了SIMetrix和SIMPLIS两款内核,为工程师提供了可靠的、易于使用的、并完美结合了速度与精度的电路仿真方式。官方的话不多说,和LTspice一样,优

gaoyong_wang的博客 2万+

全志F1C200S嵌入式驱动开发(lcd屏幕驱动)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 lcd RGB屏幕作为比较经济、实用的显示工具,在实际场景中使用较多。它的信号来说,一般也比较简单,除了常规的数据信号,剩下来就是行同步、场同步、数据使能和时钟信号了。数据信号方面,常见的格式有RGB888、RGB666、RGB565。为什么有什么多选择,主要还是取决于soc pin脚的多少来定。当然,pin脚越多,显示的颜色就越精准,还原度就越高。 举例来说,假设

嵌入式-老费,一个分享专业嵌入式知识的blog 2795

error: non-member function ‘XXX::IsValid(const T&)’ cannot have cv-qualifier

然后,我们定义了一个名为 IsValid 的全局函数,它接受一个对象作为参数,并将该对象传递给 Validator 类的构造函数。要解决这个错误,你需要将 IsValid 函数定义为一个成员函数或者一个全局函数,而不是一个非成员函数。如果你想将 IsValid 定义为一个成员函数,那么你需要将它添加到一个类中,并将需要检查的对象作为该类的成员变量。如果你不想将 IsValid 定义为一个成员函数,那么你可以将它定义为一个全局函数,并将需要检查的对象作为参数传递给它。

hanhan的博客 704

【用unity实现100个游戏之10】复刻经典俄罗斯方块游戏(附项目源码)

当今游戏产业中,经典游戏的复刻一直是一项受欢迎且具有挑战性的任务。俄罗斯方块是一个深入人心、令人上瘾的经典游戏,在过去几十年里一直享有广泛的流行度。其简单而富有策略性的玩法吸引了无数玩家的关注。因此,我决定利用Unity引擎来复刻这款经典游戏,以让更多的人重新体验其中的乐趣。通过使用Unity引擎,我能够利用其强大的工具和功能,从头开始构建一个与原版俄罗斯方块游戏相似的游戏。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2799

条款25:将constructor 和non-member function虚化

1.构造函数虚化 首先,构造函数是不能是虚函数的。见:构造函数为什么不能是虚函数  条款25所指的都是行为上类似虚构造函数,并不是真正的把构造函数实现的虚化。见MEp123. 有一种特别的virtual constructor--所谓virtual copy constructor。返回一个指针,指向其调用者(某对外)的一个新副本。 #include using namespace

HAN Kai 913

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

有些场景仍然需要 写成 non-member func进行隐式类型转换(implicit type conversion)

有些场景仍然需要 写成 non-member func进行隐式类型转换(implicit type conversion) 《Effective C++》 条款-24:若所有参数皆需类型转换,请为此采用 Non-member func() 举例: 写一个 operator*, 然后测试其交换律 结论: 当在 member func() 中,写成Entity operator* ( const Entity& e) 会造成不能隐式转换的问题; 当写成 non-member func()时候,写成Ent

GaoJuno23的博客 952

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Effective C++ 学习笔记 条款23 宁以non-member、non-friend替换member函数

如果你要在一个member函数(它不只可以访问class内的private数据,也可以取用private函数、enums、typedefs等等)和一个non-member non-friend函数(它无法访问上述任何东西)之间做抉择,而且两者提供相同机能,那么,导致较大封装性的是non-member non-friend函数,因为它并不增加“能够访问class内之private成分”的函数数量。面向对象守则要求,数据以及操作数据的那些函数应该被捆绑在一块,这意味它建议member函数是较好的选择。

tus00000的博客 820

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Effective C++之 Item 46: 需要 type conversions(类型转换)时在 templates(模板)内定义 non-member functions(非成员函数)

Item 24 阐述了为什么只有 non-member functions(非成员函数)适合于应用到所有 arguments(实参)的 implicit type conversions(隐式类型转换),而且它还作为一个示例使用了一个 Rational class 的 operator* function。我建议你在继续下去之前先熟悉那个示例,因为这个 Item 进行了针对 Item 24 中的...

janeqi1987的专栏 391

effective C++ 学习总结

effective C++ 43条,三种访问模板基类中,使用this->访问的方法 template<typename T> class A { public: void f() { cout << "A::f()" << endl; } } template<typename T> class B:public A<T> { public: void f() { .

Dave_lzw的博客 844

C/C++编程:宁以non-member、non-friend替换member函数

引入 想象有个类用来表示网页浏览器。这样的类可能提供的众多函数中,有一些用来清除下载元素高速缓冲器、清除访问过的URLs的历史记录,以及移除系统中的所有cookies: class WebBrower{ public: void clearCache(); void clearHistory(); void removeCookies(); }; 很多用户想一整个执行所有的这些动作,因此webBrowser也提供这样一个函数: class WebBrower{ public: void clear

OceanStar的博客 1676

non-member function cannot have cv-qualifier

non-member function cannot have cv-qualifier 阅读目录 在C++中CV指const和volatile— 1、非成员函数不能有CV限定,友元函数不是类的成员函数声明友元函数不能用const限定。 2、静态成员函数不能有CV限定 Q: non-member function unsigned int abs(const T&) cannot have cv-qualifier. template<typename T> ..

勿在浮沙築高台 4236

条款24(二):若所有参数皆需类型转换,请为此采用non-member函数

位于参数列的参数才会被隐式转换

不积跬步无以至千里 960

25 将constructor和non-member functions虚化

假如你写一个软件,用来处理时事新闻,其内容由文字和图形构成。你可以把程序组织成这样: class NTComponent{ //抽象基类,用于时事消息的组件 public: //其中至少含有一个纯虚函数 ... }; class TextBlock:public NTComponent{ public: ... //没有内涵任何纯虚函数 }; class Graph...

hallå的博客 281

[C++]C++重载 opeartor= must be a nonstatic member function?

codeusing namespace std;class C { public: int x; C () {} C(int a) : x(a) {} // member function C operator = (const C&); };C C::operator= (const C& param) { x = param.x; ret

需要加盐吗? 1万+

non-member function 'xxxx' cannot have cv-qualifier

不属于任何类的方法用了const修饰 解决方法:去掉const

3311

C++ 请以non-member non-friend替换member函数

20180313 C++ 请以non-member non-friend替换member函数假设有个class用来表示网页浏览器。这样的class可能提供的众多函数中,有一些用来清除缓存区;清除历史记录、移除cookies:class WebBrowser{public:  void clearCache();  void clearHistory();  void removeCookies()...

weixin_39089680的博客 638

C/C++编程:需要类型转换时请为模板定义non-member 函数

C/C++编程:如果所有参数都需类型转换,请为此采用non-member函数提出,为支持混合式算法,需要让operator*成为一个non-member函数,以允许编译期在每一个实参上执行隐式类型转换。即只有non-member函数才有能力在“所有实参身上实施隐式类型转换”。这里我们尝试用模板改写 template<typename T> class Rational{ public: Rational(const T& numerater=0, const T& denomi

OceanStar的博客 372
上一篇: [翻译] Effective C++, 3rd Edition, Item 22: 将 data members(数据成员)声明为 private
下一篇: [翻译] Effective C++, 3rd Edition, Item 24: 当希望将 type conversions(类型转换)应用于所有 parameters(参数)时,请声明为 non-member functions(非成员函数)
fatalerror99
博客等级 码龄24年 166粉丝 20原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值