条款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. 关于 java swing 使用按钮关闭窗口

    目的是给JButton添加点击操作,使指定JFrame窗口关闭. 网上不少说法是采用frame.dispose();的方法 但是采用frame.dispose();并没有使添加在frame上的wind ...

  2. Ubuntu 16.04下Java环境安装与配置

    首先下载linux下的安装包 登陆网址https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.h ...

  3. vue 实现走马灯效果

    Part.1  问题 在写一个H5页面时遇到一个需求,头部公告需要滚动变换,需要实现一个走马灯效果 Part.2  实现 我的做法:利用 定时器 + CSS3 变换公告数组的顺序 从而实现走马灯效果 ...

  4. Hermite 矩阵的特征值不等式

    将要学习 关于 Hermite 矩阵的特征值不等式. Weyl 定理 以及推论.   Weyl 定理 Hermann Weyl 的如下定理是大量不等式的基础,这些不等式要么涉及两个 Hermite 矩 ...

  5. OpenCV2:第十一章 图像转换

    一.简介 二.例子 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #inclu ...

  6. SSH整合JAR包详解

    如果要使用连接池,添加JAR : c3p0-0.9.1.2.jar

  7. 理解GloVe模型(Global vectors for word representation)

    理解GloVe模型 概述 模型目标:进行词的向量化表示,使得向量之间尽可能多地蕴含语义和语法的信息.输入:语料库输出:词向量方法概述:首先基于语料库构建词的共现矩阵,然后基于共现矩阵和GloVe模型学 ...

  8. java在线聊天项目0.1版本 制作客户端窗体,使用swing(用户界面开发工具包)和awt(抽象窗口工具包)

    建立Chat项目,并在项目中创建窗口类 package com.swift; import java.awt.BorderLayout; import javax.swing.JFrame; impo ...

  9. ajax通信

    AJAX即Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),可以在不重新加载整个网页的基础上,对网页的某部分进行更新. XMLHttpRequ ...

  10. (53)zabbix模板

    zabbix模板是做什么的? 平时工作中,我们需要监控web.mysql.redis.nginx这些服务器,众多服务器的业务都是一样的,所以我们只要事先创建好模板,然后所有服务器链接这个模板即可,如果 ...