条款18:让接口容易被正确使用,不易被误用

必须考虑客户可能做出什么样的错误(防御式编程)
std:shared_ptr会自动使用它的"每个指针专属的删除器",消除了"cross-DLL problem"(对象在DLL中被 new 创建,却在另一个DLL中 delete 销毁)

条款19:设计 class 犹如设计 type 类型系统
条款20:宁以 pass-by-reference-to-const 代替 pass-by-value

C语言永远是pass-by-value,C++默认是pass-by-value,函数参数都是以实际参数的副本拷贝为初值,函数调用的结果是函数返回值的一个副本拷贝
注意C语言中传指针方式,传指针具有引用语义,对象复制以后并没有分离,而是共享关联同一资源
采用pass-by-reference-to-const 效率高(无对象拷贝),是多态前提(基类引用),也可以避免基类和派生类之间的对象切割

条款21:必须返回局部对象时,禁止返回其reference
const Rational& operator*(const Rational& lhs, const Rational& rhs) {
Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
return result;
}

这个函数返回一个reference指向result,但result是local对象,local对象在函数退出前已经被销毁了!!!

任何函数如果返回一个reference指向某个local对象都将一败涂地
任何函数如果返回一个指针指向某个local对象同样将一败涂地

const Rational& operator*(const Rational& lhs, const Rational& rhs) {
static Rational result;
result = ...;
return result;
}

这个函数返回static对象,不具有多线程安全性,并行计算时极易出错

必须返回对象时,就让函数pass-by-value返回一个新对象

inline const Rational operator*(const Rational& lhs, const Rational& rhs) {
Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
return result;
}

这个函数以pass-by-value方式返回值语义对象,值语义对象复制之后两者分离,所以函数结束后获得的仍然是正确的对象

总结:绝不要返回reference或pointer指向一个local对象

条款22:将成员变量声明为 private

客户唯一能够访问对象成员变量的方法就是通过存取函数get()和set()
成员变量的封装性与"成员变量的内容改变时所破坏的代码量"成反比

条款23:宁以non-member、non-friend 替换member函数(本人不认同)
条款24:操作符重载时必须选择设置为类成员还是普通的非成员函数

操作符重载时,选择成员还是非成员实现有一些指导原则:
1.赋值(=)、下标([])、调用( () )、成员访问(->)必须定义为类成员,否则编译出错
2.复合赋值操作符(+=)通常定义为类成员
3.对称操作符(算术运算符、关系运算符)通常选择为non-member函数实现
注:操作符选择类成员实现时,显式形参数比操作数数目少1,因为当操作符为成员函数时,this 指向左操作数

条款25:考虑写一个不抛异常的 swap 函数

STL提供的标准swap算法如下:

namespace std {
template<typename T>
void swap(T& a, T& b) {
T temp(a);
a = b;
b = temp;
}
}

缺省版本设计到对象复制,有时效率低下。但是考虑如下:

class WidgetImpl{
public:
...
private:
int a, b, c;
std::vector<double> v;
}; class Widget{
public:
Widget(const Widget& rhs);
Widget& operator=(const Widget& rhs) {
...
*pImpl = *(rhs.pImpl);
}
private:
WidgetImpl* pImpl;
};

一旦置换两个Widget对象,唯一需要做的就是置换其pImpl指针,可以考虑模板特化技术

namespace std{
template<>
void swap<Widget>(Widget& a, Widget& b) {
swap(a.pImpl, b.pImpl); //目前还无法编译通过
}
}

上述代码中 template<> 表示它是 std:swap的一个全特化版本,函数名之后的<Widget>表示这一特化版本只针对"T是Widget"而设计(偏特化)
上述代码不能通过编译,因为a.pImpl和b.pImpl都是 private,所以进行如下改进:

class Widget{
public:
...
void swap(Widget& other) { //绝不可以抛出异常
using std::swap; //逼迫编译器使用std::swap(因为偏特化版本swap还未实现完成)
swap(pImpl, other.pImpl); //此时使用的是std::swap
}
} namespace std{
template<>
void swap<Widget>(Widget& a, Widget& b) {
a.swap(b);
}
}

一旦编译器看到对swap调用时,就会查找适当的swap调用,如果没有T专属之swap存在,编译器就会使用std内的swap

std::swap(obj1, obj2);    //错误的swap调用方式,强迫编译器总是调用std内部的swap版本
swap(obj1, obj2); //正确的swap调用方式,不带任何的命名空间修饰

c++只允许对类模板进行偏特化,不能对函数模板进行偏特化

EC++学习笔记(四) 设计与声明的更多相关文章

  1. 官网实例详解-目录和实例简介-keras学习笔记四

    官网实例详解-目录和实例简介-keras学习笔记四 2018-06-11 10:36:18 wyx100 阅读数 4193更多 分类专栏: 人工智能 python 深度学习 keras   版权声明: ...

  2. ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁

    作者:Grey 原文地址: ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁 前置知识 完成ZooKeeper集群搭建以及熟悉ZooKeeperAPI基本使用 需求 当多个进 ...

  3. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  4. IOS学习笔记(四)之UITextField和UITextView控件学习

    IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...

  5. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  6. Learning ROS for Robotics Programming Second Edition学习笔记(四) indigo devices

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  7. Typescript 学习笔记四:回忆ES5 中的类

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  8. ES6学习笔记<四> default、rest、Multi-line Strings

    default 参数默认值 在实际开发 有时需要给一些参数默认值. 在ES6之前一般都这么处理参数默认值 function add(val_1,val_2){ val_1 = val_1 || 10; ...

  9. muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制

    目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...

随机推荐

  1. iOS 随机数(Fixed)

    ios 有如下三种随机数方法: 1.    srand((unsigned)time(0));  //不加这句每次产生的随机数不变         int i = rand() % 5; 2.     ...

  2. 用navcat编写定时任务调用存储过程

    最近项目需要改动比较大,数据库结构也有所改变,这时就需要转移旧数据到新库中 第一时间想到的是用代码操作,由于两个库表结构不同,实体什么的得需要重新生成 并编写转移代码,这将是很大的工作量: 然后就想着 ...

  3. 题解 CF440A 【Forgotten Episode】

    博客阅读更好 虽然这道题是紫题,但实际难度应该是橙题吧 首先,看到标签…… 紫题?但题目也太…… 这道题教会我们不要看标签 好了,废话少说,看到楼下许多大佬都用了数组,但我觉得可以不用 为什么? 我也 ...

  4. ArcMap所有Command GUID

    The information in this topic is useful if you're trying to programmatically find a built-in command ...

  5. Bootstrap历练实例:表单控件状态(禁用的字段集fieldset)

    禁用的字段集 fieldset 对 <fieldset> 添加 disabled 属性来禁用 <fieldset> 内的所有控件. <!DOCTYPE html>& ...

  6. rsync文档

    rsync文档 1.rsync filter过滤 参考http://share.blog.51cto.com/278008/567578/

  7. 学习笔记之30个常用的maven命令

    maven 命令的格式为 mvn [plugin-name]:[goal-name],可以接受的参数如下, -D 指定参数,如 -Dmaven.test.skip=true 跳过单元测试: -P 指定 ...

  8. javascript(九)事件冒泡 onmouseenter onmouseenter 默认事件 和 键盘事件

    1 事件冒泡 子元素触发的事件,会往上(父元素)传递: 例子: <div id="box"> <p></p> </div> < ...

  9. 【Python学习之二】装饰器

    装饰器 首先,给出装饰器的框架: def log(func): def wrapper(*args, **kw): print('call %s():' % func.__name__) return ...

  10. tkinter学习-选择按钮

    阅读目录 Checkbutton Radiobutton LabelFrame checkbutton : 说明:多选框控件,用于在程序中提供多项选择框,但是处理“多选一”的问题,还是交给 Radio ...