Effective C++:条款23:宁以non-member、non-friend替换member函数

本文探讨了C++编程中封装的重要性,比较了使用成员函数和非成员函数实现功能的影响,并介绍了如何通过命名空间组织工具函数以提高封装性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(一)

有个class来表示网页浏览器:

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

很多用户会想一整个运行全部这些动作,因此WebBrowser也提供这样一个函数:clearEverything

class WebBrowser { 
public: 
    void clearChache(); 
    void clearHistory(); 
    void removeCookies(); 
    void clearEverything(); 
};

当然也能够由一个non-member函数调用适当的member函数而提供出来:

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

那么哪一个比較好呢?是member函数clearEverything()还是non-member函数claseBrower呢。

越多东西被封装,我们改变那些东西的能力也就越大。对象内的数据。越少代码看到它(訪问它),越多的数据可被封装,也就越能自由地改变对象数据,比如改变成员变量的数量。类型等等。

所以答案当然是non-member函数claseBrower。由于它导致了较大的封装性。由于它并不添加“能过訪问class内之private成分”的函数数量。这就解释了为什么clearBrowser(一个non_member non-friend函数)比clearEverything(一个member函数)更受欢迎的原因:它导致WebBrowser class有较大的封装性。

可是这里有两件事情要注意下:

第一:这里仅仅适用于non-member non-friend函数。

friend函数对class private成员的訪问权力和member函数同样,因此两者对封装的冲击也同样。
第二:仅仅因在意封装而让函数“成为class 的non-member”,并不意味着它“不能够是还有一个class的member”。假如我们能够另clearBrowser成为某工具类(utility class)的一个static member函数。

(二)

在C++中,比較自然的做法是让clearBrowser成为一个non-member函数而且位于WebBrowser所在的同一个namespace(命名空间)内:

namespace WebBrowserStuff{ 
    class WebBrowser{...}; 
    void clearBrowser(WebBrowser wb); 
}

像clearBrowser这种函数是个“提供便利的函数”。一个像WebBrowser这种class可能拥有大量的便利函数,某些与书签有关,某些与打印有关。某些与cookie的管理有关…,通常,大多数客户仅仅对当中某些感兴趣。

没有道理一个仅仅对书签感兴趣的客户却与一个cookie相关便利函数发生编译相依关系。

分离他们最直接的方法是将他们放入不同的头文件:

//头文件webbrowser.h这一头文件针对class WebBrowser自身以及WebBrowser核心机能。

namespace WebBrowserStuff{ 
    void clearBrowser(WebBrowser wb); 
    ...//WebBrowser核心机能,差点儿全部客户都须要的non-member函数。

} //头文件“webbrowserbookmarks.h” namespace WebBrowserStuff{ class WebBrowser{...}; ...//与书签相关的便利函数 } //头文件“webbrowsercookies.h” namespace WebBrowserStuff{ class WebBrowser{...}; ...//与cookie相关的便利函数 }

C++标准程序库正是这种组织方式。数十个头文件,每一个头文件声明std的某些机能。

假设仅仅想使用vector不用#include <memory>;假设不想使用list也不须要#include <list>.这同意客户仅仅对他们所用的那一小部分系统形成编译相依。这种分割机能并不适合class成员函数,由于class 必须总体定义,不能被分割为片段。

namespace能够跨越多个源代码文件,而class不能。

将全部便利函数放在多个头文件里但隶属同一个命名空间,意味着客户能够轻松扩展这一组便利函数。

他们所要做的就是加入很多其它non-member non-friend函数到此命名空间内。比如:假设客户想写些与影像下载相关的便利函数。仅仅要在WebBrowserStuff命名空间内建立一个头文件。内含那些函数的声明就可以。新函数就像其它旧函数一样可用且整合为一体。这是class无法提供的还有一个性质,由于class定义对客户是不能扩展的。



请记住:

尽量用non-member non-friend函数替换member函数。能够添加封装性、包裹弹性(packaging flexibility)、和机能扩充性。






转载于:https://www.cnblogs.com/xfgnongmin/p/10633212.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值