标签:effective c++ 成员函数 类型转换 封装性
class AccessLevels{ public: …… int getReadOnly() const {return readOnly;} void setReadWrite(int value){readWrite=value;} int getReadWrite()const{return readWrite;} void setWriteOnly(int value){writeOnly=value;} private: int noAccess;//无任何访问动作 int readOnly;//只能读 int readWrite;//能读能写 int writeOnly;//只能写 };
class SpeedDataCollection{ …… public: void addValue(int speed);//添加一笔新数据 double averageSoFar() const;//返回平均速度 …… };
这个条款讲解成员函数和友函数的区别。
考虑一个class用来清除浏览器的一些记录,这个class中有清除告诉缓存区的函数,有清除访问过URLs的函数,还有清除cookies的函数:
class WebBrowser{ public: …… void clearCash(); void clearHistory(); void removeCookies(); …… };一般情况下,需要同时执行这三个动作,因此WebBrowser可以提供这样一个函数:
class WebBrowser{ public: …… void clearEverything() { clearCash(); clearHistory(); removeCookies(); } …… };
void clearBrowser(WebBrowser& wb) { wb.clearCash(); wb.clearHistory(); wb.removeCookies(); };
面向对象思想要求,数据尽可能被封装,member函数clearEverything带来的封装性比non-member函数clearBrowser低。提供non-member函数,对class相关机能有较大包裹弹性(packaging flexibility),因此带来了较低的编译相依度,增加了class的可延展性。
封装意味着不可见。愈多东西被封装,欲少人可以看到它,我们就有愈大的弹性去改变它。愈少代码可以看到数据(访问数据),愈多数据可被封装,我们就更有自由来改变对象数据。愈多函数可以访问它,数据的封装性就愈低。
条款22有讲到,成员变量应该是private,否则就有无限多函数可以访问它,毫无封装可言。能访问private成员变量的函数只有class的member函数、friend函数而已。在一个member函数和一个non-member、non-friend函数之间做抉择,如果两者提供相同的机能,显然后者提供了更大的封装,这个就是上面选择clearBrowser函数的原因。
在封装这点上,需要注意两点。1、这个论述只适用于non-member、non-friend函数。2、因为封装,让函数成为class的non-member函数,但这并不意味着它不可以是另一个class的member函数。
在C++中,实现上述功能,比较自然的做法是把clearBrowser函数和WebBrowser类放到一个命名空间内:
namespace WebBrowserStuff{ class WebBrowser{……}; void clearBrowser(WebBrowser& we); …… }
//头文件webbrowser.h,这个头文件针对class WebBrowser自身及WebBrowser核心机能 namespace WebBrowserStuff{ class WebBrowser{……};//核心机能 ……//non-member函数 } //头文件webbrowserbookmarks.h namespace WebBrowserStuff{ ……//与书签相关的便利函数 } //头文件webbrowsercookies.h namespace WebBrowserStuff{ ……//与cookie相关的便利函数 }
将所有便利函数放到多个文件夹但隶属同一个命名空间,意味着客户可以轻松扩展这一组便利函数,他们要做的就是往命名空间添加更多non-member函数和non-friend函数,这也是class无法做到的。当然客户可以继承类来扩展出新类,但是derived class无法访问base class中封装的private成员,因此扩展的机能拥有的只是次级身份。
总结:用non-member、non-friend函数替换member函数,这样可以增加封装性、包裹弹性和机能扩充性。
通常情况,class不应该支持隐式类型转换,因为这样可能导致我们想不到的问题。这个规则也有例外,最常见的例外是建立数值类型时。例如编写一个分数管理类,允许隐式类型转换
class Rational{ public: Rational(int numerator=0, int denominator=1);//非explicit,允许隐式转换 …… };如果要支持加减乘除等运算,这时重载运算符时是应该重载为member函数还是non-member函数呢,或者non-member friend函数?
class Rational{ public: …… const Rational operator*(const Rational& rhs); …… };
Rational onEight(1,8); Rational oneHalf(1,2); Rational result=onEight*oneHalf; result=result*onEight;如果进行混合运算
result=oneHalf*2;//正确,相当于oneHalf.operator*(2); result=2*oneHalf;//错误,相当于2.operator*(oneHalf);
const Rational operator*(const Rational& lhs, const Rational& rhs);
标签:effective c++ 成员函数 类型转换 封装性
原文地址:http://blog.csdn.net/kangroger/article/details/43501669