条款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. 将sql 查询结果导出到excel

    在平时工作中经常会遇到,sql 查询数据之后需要发送给业务人员,每次都手工执行脚本然后拷贝数据到excel中,比较耗时耗力,可以考虑自动执行查询并将结果邮件发送出来. 分两步实现: 1.执行查询将结果 ...

  2. 如何在ABAP里用函数式编程思想打印出非波拉契Fibonacci(数列)

    在JavaScript里可以用ES6提供的FunctionGenerator这种黑科技来打印非波拉契数列,具体细节参考我这篇文章. 在ABAP里也有很多种方式实现这个需求. 下面这个report分别用 ...

  3. caffe的调试技巧 和 使用split层

    1.网络中的layer层的输出,只要没有作为其他层的输入,caffe的日志就会把这个top输出(如果你用那个网站画网络结构图,你也会发现这种情况的层的颜色是不一样的,是紫色的) 2.如果你想看某一层在 ...

  4. tp5 -- 微信公众号支付

    近来期间比较忙, 忙完之后发现最近有挺多的东西没有整理,于是乎.就将以前用到的一些小东西整理了一下. 如果对您有帮助,则是我最大的幸运. 本篇主要是说了一下整合TP5的微信公众号支付. 不过由于最近T ...

  5. 如何优化sql查询

    借鉴https://www.cnblogs.com/ssrstm/p/5753068.html和https://www.cnblogs.com/exe19/p/5786806.html 1. 对查询进 ...

  6. MySQL 上移/下移/置顶

    在编写网站系统时,难免会用到上移.下移.置顶的功能,今天小编就介绍一下我的思路. 首先,需要一张数据表: CREATE TABLE `a` ( `id` ) NOT NULL AUTO_INCREME ...

  7. mycat中间件安装与使用

    前提: 安装JDK版本在7.0及其以上 1.下载: 下载地址在:http://dl.mycat.io/ 选择1.6-release版本下载 2.安装: 直接解压即可: tar -zxf Mycat-s ...

  8. (34)zabbix Queue队列

    概述 queue(队列)显示监控项等待刷新的时间,可以看到每种agent类型刷新时间,通过queue可以更好的体现出监控的一个指标.正常情况下,是一片绿色. 如果出现过多红色,那么需要留意一下.我们也 ...

  9. Git学习——版本切换

    版本回退 回退到前面几个版本的命令如下: git reset --hard HEAD^ //回退到前一个版本 git reset --hard HEAD^^ //回退到前前一个版本 git reset ...

  10. docker 安装 openresty

    文章来源: 1.拉取镜像 # docker pull openresty/openresty 2.启动openresty # docker run -it --name openresty -p : ...