快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

和记娱最好h88285愽娱:C++箴言用非成员非友元函数取代成员函数



想象一个象征 web 浏览器的类。在大年夜量的函数中,这样一个类大概会供给清空已下载因素的缓存。清空已造访 URLs 的历史,以及从系统移除所有 cookies 的功能:

class WebBrowser {

public:

...

void clearCache();

void clearHistory();

void removeCookies();

...

};

很多用户盼望能一路履行整个这些动作,以是 WebBrowser 可能也会供给一个函数去这样做:

class WebBrowser {

public:

...

void clearEverything(); // calls clearCache, clearHistory,

// and removeCookies

...

};

当然,这个功能也能经由过程非成员函数调用适当的成员函数来供给:

void clearBrowser(WebBrowser& wb)

{

wb.clearCache();

wb.clearHistory();

wb.removeCookies();

}

那么哪个更好呢和记娱最好h88285愽娱,成员函数 clearEverything 照样非成员函数 clearBrowser?

面性工具原则指出:数据和对它们进行操作的函数应该被绑定到一路,而且建议成员函数是更好的选择。不幸的是,这个建议是不精确的。它孕育发生于对面向工具是什么的一个误解。面向工具原则指出数据应该尽可能被封装。与直觉不合,成员函数 clearEverything 居然会造成比非成员函数 clearBrowser 更差的封装性。此外,供给非成员函数容许 WebBrowser 相关功能的更大年夜的包装弹性,而且,可以得到更少的编译依附和 WebBrowser 扩展性的增进。因而,在很多方面非成员措施比一个成员函数更好。理解它的缘故原由是异常紧张的。

我们将从封装开始。假如某物被封装,它被从视线中暗藏。越多的器械被封装,就越少有器械能望见它。越少有器和记娱最好h88285愽娱械能望见它,我们改变它的弹性就越大年夜,由于我们的改变仅仅直接影响那些能望见我们变了什么的器械。某物的封装性越强,那么我们改变它的能力就越强。这便是将封装的代价评价为第一的缘故原由:它为我们供给一种改变工作的弹性,而仅仅影响有限的客户。

结合一个工具斟酌数据。越少有代码能看到数据(也便是说,造访它),数据封装性就越强,我们改变工具的数据的特点的自由也就越大年夜,比如,数据成员的数量,它们的类型,等等。作为若干代码能看到一块数据的粗拙的尺度,我们可以计数能造访那块数据的函数的数量:越多函数能造访它,数据的封装性就越弱。

数据成员应该是 private 的,由于假如它们不是,就有无限量的函数能造访它们。它们根本就没有封装。对付 private 数据成员,能造访他们的函数的数量便是类的成员函数的数量加上友元函数的数量,由于只有成员和友元能造访 private 成员。假设在一个成员函数(能造访的不光是一个类的 private 数据,还有 private 函数,罗列,typedefs,等等)和一个供给同样功能的非成员非友元函数(不能造访上述那些器械)之间有一个选择,能得到更强封装性的选择长短成员非友元函数,由于它不会增添能造访类的 private 部分的函数的数量。这就说清楚明了为什么 clearBrowser(非成员非友元函数)比 clearEverything(成员函数)更可取:它能为 WebBrowser 得到更强的封装性。

在这一点,有两件事值得留意。首先,这个论证只适用于非成员非友元函数。友元能像成员函数一样造访一个类的 private 成员,是以同样影响封装。从封装的不雅点看,选择不是在成员和非成员函数之间,而是在成员函数和非成员非友元函数之间。(当然,封装并不是仅有的不雅点,假如不雅点来自隐式类型转换,选择便是在成员和非成员函数之间。)

必要留意的第二件事是,假如仅仅是为了关注封装,则可以指出,一个函数是一个类的非成员并不料味着它弗成所以另一个类的成员。这对付习气了所有函数必须属于类的说话(例如,Eiffel,Java,C#,等等)的法度榜样员是一个适度的劝慰。例如,我们可以使 clearBrowser 成为一个 utility 类的 static 成员函数。只要它不是 WebBrowser 的一部分(或友元),它就不会影响 WebBrowser 的 private 成员的封装。

在 C++ 中,一个更自然的措施是使 clearBrowser 成为与 WebBrowser 在同一个 namespace(名字空间)中的非成员函数:

namespace WebBrowserStuff {

class WebBrowser { ... };

void clearBrowser(WebBrowser& wb);

...

}

相对付形式上的自然,这样更适用于它。无论若何,由于名字空间(不像类)能展开到多个源文件中。这是很紧张的,由于类似 clearBrowser 的函数是方便性函数。作为既不是成员也不是友元,他们没有对 WebBrowser 进行专门的造访,以是他们不能供给任何一种 WebBrowser 的客户不能经由过程其它措施获得的功能。例如,假如 clearBrowser 不存在,客户可以直接调用 clearCache,clearHistory 和 removeCookies 本身。

一个类似 WebB和记娱最好h88285愽娱rowser 的类可以有大年夜量的方便性函数,一些是书签相关的,另一些打印相关的,还有一些是 cookie 治理相关的,等等。作为一个一样平常的常规,多半客户仅对这些方便性函数的聚拢中的一些感兴趣。没有来由让一个只对书签相关的方便性函数感兴趣的客户在编译时依附其它函数,例如,cookie 相关的方便性函数。分隔它们的刀切斧砍的措施便是在一个头文件中声明书签相关的方便性函数,在另一个不合的头文件中声明 cookie 相关的方便性函数,在第三个头文件声明打印相关的方便性函数,等等:

// header "webbrowser.h" - header for cl和记娱最好h88285愽娱ass 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 "w和记娱最好h88285愽娱ebbrowsercookies.h"

namespace WebBrowserStuff {

... // cookie-related convenience

} // functions

...

留意这里就像标准 C++ 库组织得一样缜密。胜于有一个零丁的一体式的 <C++StandardLibrary> 头文件包孕 std namespace 中的所有器械,它们在许多头文件中(例如,<vector>,<algorithm>,<memory>,等等),每一个都声清楚明了 std 中的一些性能。仅仅必要 vector 相关性能的客户不必要 #include <memory>,不用 list 的客户没有需要 #include <list>。这就容许客户在编译时仅仅依附他们实际应用的那部分系统。当性能来自一个类的成员函数时,用这种措施瓜分它是弗成能的,由于一个类必须作为一个整体来定义,它不能四分五裂。

将所有方便性函数放入多个头文件中——然则在一个 namespace 中——也意味着客户能轻易地扩充方便性函数的聚拢。他们必须做的整个便是在 namespace 中加入更多的非成员非友元函数。例如,假如一个 WebBrowser 的客户抉择写一个关于下载图像的方便性函数,他或她仅仅必要新建一个头文件,包孕那些函数在 WebBrowserStuff namespace 中的声明。这个新的函数现在就像其它方便性函数一样可用并被集成。这是类不能供给的另一个特点,由于类定义对付客户是扩充封闭的。当然,客户可以派生新类,然则派生类不能造访基类中被封装的(也便是说,private 的)成员,以是这样的“扩充性能”只有二等身份。此外,不是所有的类都是作为基类设计的。

Things to Remember

用非成员非友元函数取代成员函数。这样做可以前进封装性,包装弹性,和性能扩充性。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: