《Effective C++ 3th》——设计与声明
文章目录
- 友好的接口设计
- member与non-member函数设计
- 不抛异常的swap函数设计
让接口容易被正确使用,不易被误用
设计class犹如设计type
宁以pass-by-reference-to-const替换pass-by-value
必须返回对象时,别妄想返回其reference
将成员变量声明为private
宁以non-member、non-friend替换member函数
若所有参数皆须类型转换,请为此采用non-member函数
考虑写出一个不抛异常的swap函数
友好的接口设计
引入类:
class Time
{public:Time();~Time();Time* createTime();...void setTime(int hour, int minute, int second);...
};
一切都是为了接口的友好,必须要考虑以下两个问题:
- 用户可以给什么?
- 可以给用户什么?
用户可以给什么即用户的参数怎么传递,如何通过参数的结构化设计来避免用户传参时的茫然。针对 setTime
函数:
// 普通设计
void setTime(int hour, int minute, int second) {...}// 参数结构化
struct HOUR {...} // 或 enum HOUR {...}
struct MINUTE {...} // 或 enum MINUTE {...}
struct SECOND {...} // 或 enum SECOND {...}
void setTime(HOUR hour, MINUTE min, SECOND sec);
通过对参数封装实现输入参数限制,接口更友好。但这种设计是否必要?我不禁想起各种开源的神级软件,例如ffmpeg、vlc等等不胜枚举,参数真的是晦涩…此外,增加函数内部检查即可有效避免参数错误情况,不过如果是做开放API则遵循这些友好建议是相当不错的。
可以给用户什么如出一辙,针对 createTime
函数,创建的对象指针最后需要被释放,为了避免忘记可以将对象指针放入智能指针,但何不一开始 createTime
就直接返回智能指针呢?
唔,这种强烈交互性需求必然要求像设计C++内置type一样去设计自己的类。这对于大众码农来说当然是很高的要求了,不然何不写个自己的语言呢?
封装层面的暂且不说,来谈谈性能层面。
int compare(Time tm) {...}int compare(const Time &tm) {...}
区别在哪?Time tm
会在传递过程中产生临时变量和复制操作,而 const Time &tm
则不会产生额外变量,可以减少的性能耗费当然是尽量减少了。之前网上不少网友因为 std::string
作为参数传递为什么要传 const std::string &
而大打出手,Qt那边也有 QString
与 const QString &
相同疑问,想必这样应该会对 使用引用传递替代值传递 有更加深刻的认识。
再看:
const Rational& operator*(const Rational &lhs, const Rational &rhs)
{Rational result(lhs.n * rhs.n, lhs.d * rhs.d);return result;
}const Rational& operator*(const Rational &lhs, const Rational &rhs)
{Rational *result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);return *result;
}
这些都是翻车代码,返回给用户的都是埋雷的引用。情况一的result由stack分配,函数返回时它的内存理当销毁,那要它的引用有何用?情况二的result确实由heap分配,但谁负责销毁?
member与non-member函数设计
考虑程序:
class WebBrowser
{public:...void clearCache();void clearHistory();void removeCookies();...// member封装调用void clearEverything(); // 调用clearCache、clearHistory和removeCookiesprivate:bool cleared; // 成员变量应尽量private
};// non-member封装调用
void clearBrowser(WebBrowser &wb)
{wb.clearCache();wb.clearHistory();wb.removeCookies();
}
member封装调用和non-member封装调用哪个好?non-member函数允许对WebBrowser相关机能有较大的包裹弹性,可增加WebBrowser的可延展性。
事实上,WebBrowser提供网络访问的最基本封装,而clear操作则是针对WebBrowser的业务封装,建议将这两部分的代码独立出来。而如果非要选择的话还是non-member更好些,除非提供额外的类来替代non-member的功能。
其次,变量成员都声明成 private
也并非必须,不能说 public
的改动可能波及范围大就摒弃 public
和 protected
型的成员变量,在没有明确期望成员变量何时可见的时候,我们不妨使用中庸的 protected
,而当目标明确的时候,限定符的选择自然也就不会成为问题。
针对算术运算的member与non-member比较:
class Rational
{public:...const Rational operator*(const Rational &rhs) const; // member...
};// non-member
const Rational operator*(const Rational &lhs, const Rational &rhs)
{return Rational(lhs.numerator() * rhs.numerator(),lhs.denominator() * rhs.denominator());
}
此时的member并不能完全实现混合运算,而non-member声明的函数却可以:
// member
Rational oneEighth(1, 8);
Rational oneHalf(1, 2);
Rational result = oneHalf * oneEighth; // success
result = result * oneEighth; // success
result = oneHalf * 2; // success
result = 2 * oneHalf; // error// non-member
result = oneHalf * 2; // success
result = 2 * oneHalf; // success
这是因为member只是属于类的操作符重载,由类主导;而non-member对两个操作数平等对待,自然可以对所有参数进行隐式的类型转换。
总结而言:针对功能需求合理选择member与non-member函数实现。
不抛异常的swap函数设计
略
《Effective C++ 3th》——设计与声明相关推荐
- Effective C++ --4 设计与声明
上一部分Effective C++ --3 资源管理 18.让接口容易被正确使用,不易被误用 (1)设计接口时要考虑客户可能可能做出的错误输入,如参数的形式等. 19.设计class犹如设计type ...
- 《Effective C++ 3th》——后记
像<Effective C++ 3th>这类书,在C++进阶阶段必不可少.总结而言,书中内容主要分为以下几块: 减少出错的良好编程习惯/原则: 降低资源利用的有效策略: 深入理解OOP的精 ...
- effective java 3th item2:考虑 builder 模式,当构造器参数过多的时候
yiaz 读书笔记,翻译于 effective java 3th 英文版,可能有些地方有错误.欢迎指正. 静态工厂方法和构造器都有一个限制:当有许多参数的时候,它们不能很好的扩展. 比如试想下如下场景 ...
- Effective C++ ——设计与声明
条款18:让接口更容易的被使用,不易误用 接口设计主要是给应用接口的人使用的,他们可能不是接口的设计者,这样作为接口的设计者就要对接口的定义更加易懂,让使用者不宜发生误用,例如对于一个时间类: cla ...
- 《Effective C++ 3th》——继承与面向对象设计
文章目录 Is A 确定你的public继承塑模出is-a关系 避免遮掩继承而来的名称 区分接口继承和实现继承 考虑virtual函数以外的其他选择 绝不重新定义继承而来的non-virtual函数 ...
- EC++学习笔记(四) 设计与声明
条款18:让接口容易被正确使用,不易被误用 必须考虑客户可能做出什么样的错误(防御式编程) std:shared_ptr会自动使用它的"每个指针专属的删除器",消除了"c ...
- effective java 3th 序
正本基本是自己翻译,翻译绝对有错误,就是这么自信,看的时候,自己注意下,如果感觉有语句不通,那么可能就是我翻译的出现了问题,可以自己翻找原文对比下. 其中自己的见解,我写在脚注中. 在 1997 年, ...
- 《Effective C++ 3th》——实现
文章目录 写精简的程序 写安全的程序 写低耦合的程序 尽可能延后变量定义式的出现时间 尽量少做转型动作 避免返回handles指向对象内部成分 为"异常安全"而努力是值得的 透彻了 ...
- 《Effective C++ 3th》——资源管理
文章目录 资源如何释放? 注意资源的唯一性 由使用智能指针引出的问题 以对象管理资源 在资源管理类中小心coping行为 在资源管理类中提供对原始资源的访问 成对使用new和delete时要采取相同形 ...
最新文章
- 高效学习方法论的学习笔记
- 美团配送数据治理实践
- k8s service服务发现详解:ipvs代理模式、服务类型
- ConcurrentHashMap的源码分析-JDK1.7和Jdk1.8版本的变化
- 连不到别人电脑的mysql_连接其他电脑mysql (转)
- 中南大学和中山大学计算机专业哪个好,中山大学和中南大学哪个实力更强?一字之差,一起来看看吧!...
- 前台setcookie之后从后台取出来_后台设置Cookie值,前台进行获取
- 列表应用(导航菜单)
- 三、JVM — 类加载过程
- 【面经】关于逻辑回归,面试官们都怎么问
- TabBars代码解读之——Visual Studio的自动化接口
- 数据-第17课-栈课后练习
- 自动化测试工具-Airtest
- Linux服务篇之SSH服务
- 免费云服务器(阿贝云服务器入门)(仅适用于windows server系统)
- eda交通灯控制器波形输入_EDA实验报告实验四:交通灯控制器设计
- 使用c语言实现后缀表达式计算器
- 工作中一个管理者的态度
- 苹果电脑怎么打印cpa准考证
- 实现Python Http 接口测试