EC读书笔记系列之12:条款22、23、24
条款22 将成员变量声明为private
记住:
★切记将成员变量声明为private。这可赋予客户访问数据的一致性、可细微划分访问控制、允诺约束条件获得保证,并提供class作者以充分的实现弹性。
★protected并不比public更具封装性
条款23 宁以non-member-non-friend替换member函数
记住:
★宁可拿non-member-non-friend函数替换member函数。这样可增加封装性、包裹弹性和机能扩充性。
-------------------------------------------------------------------------------
举例:
class WebBrowser {
...
void clearCache(); //清除缓存
void clearHistory();//清除历史
void clearCookies();//清除cookies
...
};
假设想一次性执行上面三个有关清理的函数,有两种方法:
方法一:将这个一次性清理工作函数写成member function:
class WebBrowser {
public:
...
void clearEverything(); //调用上面的三个函数
...
};
方法二:写成non-member-non-friend函数:
void clearBrowser( WebBrowser &wb ) {
wb.clearCache();
wb.clearHistory();
wb.clearCookies();
}
方法二要好一点!!!因为non-member函数将导致较大的封装性,∵其并不能访问class内部的private成分。(因为对于对象内的数据来说,愈少代码可以看到数据,也即访问它,愈多的数据就可被封装,而我们也就愈能自由地改变对象的数据,这不也就是封装性的体现吗!!)
两件需要注意的事:
一、上述论述仅适用于no-member-non-friend函数;
二、因在意封装性而让函数“成为class的non-member”,并不意味着其“不可以是另一个class的member”
推荐做法:
让clearBrowser成为一个non-member并且位于WebBrowser所在的同一个namespace内:
namespace WebBrowserStuff {
class WebBrowser {...};
void clearBrowser( WebBrowser &wb );
...
} //注意namespace这里无分号!!!
注:像上面WebBrowser这样的class可能拥有多种便利函数,如某些与书签有关,某些与打印有关等。可以将这些便利函数的编译相依关系降低:分离他们的直接做法是将书签相关的便利函数声明于一个头文件,将打印相关的便利函数声明于另一个头文件:
namespace WebBrowserStuff {
class WebBrowser{...}; //核心机能
}
//头文件"webbrowserbookmark.h"
namespace WebBrowserStuff {
... //与书签相关的便利函数
}
//头文件"webbrowserprint.h"
namespace WebBrowserStuff {
... //与打印相关的便利函数
}
以此种方式切割机能并不适用于member函数,因为一个class必须整体定义,不能被分割为片段,从这个角度来说也符合本条款的主题。
条款24 若所有参数皆需类型转换,请为此采用non-member函数
记住:
★若需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么此函数必须是个non-member。
-------------------------------------------------------------------------------
举例:有理数类
class Rational {
public:
Rational( int numerator = ,
int denominator =
); //构造函数刻意不为explicit,
//这样做是为了int-to-Rational隐式转换
...
};
现让该有理数类支持乘法运算。现将operator*写为类的member函数:
class Rational {
public:
...
const Rational operator*( const Rational &rhs ) const;
};
若下面这样用:
Rational oneEighth( , );
Rational oneHalf( , );
Rational result;
result = oneHalf*oneEighth; //用法1:可以
result = oneHalf*; //用法2:可以
result = *oneHalf; //用法3:错误
这里的用法2,之所以行得通,是因为这里发生了隐式类型转换,等价于下面这样调用:
const Rational temp(2); //建立一个暂时性的Rational对象
result = oneHalf*temp; //等价于oneHalf.operator*( temp );
当然这种做法可行的前提是non-explicit constructor!!!
仅当参数被列于参数列内,此参数才是隐式类型转换的合格参与者,这是用法2和用法3的区别。
解决方案:将operator*写成non-member函数,这样便可以使在每一个实参身上执行隐式类型转换!!!
const Rational operator*( const Rational &lhs,
const Rational &rhs
) { return Rational( lhs.numerator() * rhs.numerator(),
rhs.denominator() * rhs.denominator()
);
}
这样:
result = oneHalf*;
result = *oneHalf; //也可以通过编译了!!!
注意:
member函数的反面是non-member函数,而不是friend函数!!!(因为有太多的C++程序员错误地认为若一个“与某class相关”的函数不该成为一个member,就该是个friend)
EC读书笔记系列之12:条款22、23、24的更多相关文章
- EC读书笔记系列之7:条款12 复制对象时勿忘其每一个成分
记住: ★copying函数应确保复制“对象内的所有成员变量”及“所有base class成分” ★不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两 ...
- EC读书笔记系列之16:条款35、36、37、38、39、40
条款35 考虑virtual函数以外的其他选择 记住: ★virtual函数的替代方案包括NVI手法及Strategy模式的多种形式.NVI手法自身是一个特殊形式的Template Method模式 ...
- EC读书笔记系列之1:条款1、条款2、条款3
条款1:视C++为一个语言联邦 记住: ★C++高效编程守则视状况而变化,这取决于你使用C++的哪一部分 C: Object-oriented c++: Template c++: STL 条款2:尽 ...
- EC读书笔记系列之20:条款53、54、55
条款53 不要轻忽编译器的警告 记住: ★严肃对待编译器发出的警告信息.努力在你的编译器的最高(最严苛)警告级别下争取“无任何警告”的荣誉 ★不要过度依赖编译器的报警能力,∵不同的编译器对待事情的态度 ...
- EC读书笔记系列之19:条款49、50、51、52
条款49 了解new-handler的行为 记住: ★set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用 ★Nothrow new是一个颇为局限的工具,∵其只适用于内存 ...
- EC读书笔记系列之18:条款47、48
条款47 请使用traits classes表现类型信息 记住: ★Traits classes使得“类型相关信息”在编译期可用.它们以templates和“templates特化”完成实现 ★整合重 ...
- EC读书笔记系列之17:条款41、42、43、44、45、46
条款41 了解隐式接口与编译器多态 记住: ★classes和templates都支持接口和多态 ★对classes而言接口是显式的(explicit),以函数签名为中心.多态则是通过virtual函 ...
- EC读书笔记系列之15:条款32、33、34
条款32 确保你的public继承塑模出is-a关系 记住: ★public继承意味着is-a.适用于base class身上的每一件事情一定也适用于derived class身上,∵每一个deriv ...
- EC读书笔记系列之14:条款26、27、28、29、30、31
条款26 尽可能延后变量定义式的出现时间(Lazy evaluation) 记住: ★尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率 ----------------------- ...
随机推荐
- C#接口的使用【转】
我们定义一个接口public interface IBark{ void Bark();}再定义一个类,继承于IBark,并且必需实现其中的Bark()方法public class Dog:IBa ...
- 开源企业IM-免费企业即时通讯-ENTBOOST V2014.180 Linux版本号正式公布
ENTBOOST,VERSION 2014.180 Linux版本号公布,主要添加企业IM应用集成功能,完好安卓SDK功能及部分BUG修正: 7/1(明天)公布Windows版本号,敬请关注! ENT ...
- 小米手机与魅族的PK战结果 说明了什么
我国电子商务面临的问题,淘宝退出百度无疑是一个遗憾.当在网上购物时.用户面临的一个非常大的问题就是怎样在众多的站点找到自己想要的物品,并以最低的价格买到.自从淘宝退出百度.建立自己的搜索引擎后,广大消 ...
- 加濾鏡效果GlowTween
/** * * new GlowTween(xxxx, 0xFFFF00); * new GlowTween(xxxx, 0x00FFFF); * GlowTween */ package com.r ...
- 高性能浏览器网络(High Performance Browser Networking) 第二章
第2章 TCP篇 互联网的核心是两个协议,IP和TCP. IP也叫Internet协议,提供主机到主机的路由和寻址:TCP,传输控制协议,在不可靠的传输通道上提供一个可靠的网络抽象.TCP / IP协 ...
- 《编写可维护的JavaScript》之编程实践
最近读完<编写可维护的JavaScript>,让我受益匪浅,它指明了编码过程中,需要注意的方方面面,在团队协作中特别有用,可维护性是一个非常大的话题,这本书是一个不错的起点. 本书虽短,却 ...
- Array数组方法的总结
添加元素: 1. push(arg1,arg2,arg3....) 向数组的尾部添加元素,返回值是数组的长度. 2.unshift(arg1,arg2,arg3....) 向数组的头部添加元素,返回 ...
- ThInkPHP中的常量
除了常规变量的输出外,模板引擎还支持系统变量和系统常量.以及系统特殊变量的输出.它们的输出不需要事先赋值给某个模板变量.系统变量的输出必须以$Think.打头,并且仍然可以支持使用函数.常用的系统变量 ...
- textarea
■ 摘要 项目 说明 形式 <textarea>-</textarea> 支持 H2+ / e2+ / N2+ / Fx1+ / Op6+ / Ch1+ / Sa1+ 标签省略 ...
- C# 中的委托和事件详解
C# 中的委托和事件 文中代码在VS2005下通过,由于VS2003(.Net Framework 1.1)不支持隐式的委托变量,所以如果在一个接受委托类型的位置直接赋予方法名,在VS2003下会报错 ...