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

  • 注意使用const,explicit,shared_ptr等来限制接口。
  • 必要时可以创建一些新的类型,限制类型操作,束缚对象等。
  • 注意保持接口的一致性,且与内置类型的行为兼容。
class Month {
public:
static Month Jan(){return Month(1);}
static Month Feb(){return Month(2);}
...
static Month Dec(){return Month(12);}
private:
explicit Month(int m) : val(m){}
int val;
};

条款19:设计class犹如设计type

  • 对象的创建和销毁

    • 构造函数和析构函数的设计
  • 对象的初始化和赋值
    • 构造函数和赋值操作符的设计及其之间的差别
  • 对象被以值传递(pass by value)
    • copy构造函数的设计
  • 有效的对象
    • class中一些成员变量是受约束的,决定了成员函数(特别是构造函数,赋值操作符和所谓的"setter"函数)必须进行检查工作。
  • 新type用于继承中
    • 继承自现有classes,就会受到这些classes的束缚,特别是受它们"virtual"和"non-virtual"成员函数的影响。
    • 被继承,要考虑所声明的函数(特别是析构函数)是否为virtual
  • 新type的转换
    • 类型T1隐式转换为类型T2,可在class T1中写一个类型转换函数(operator T2() const)或在class T2中写一个构造函数(T2(T1))
  • 为type设计合理的操作符和函数
  • 一些函数要被驳回不可调用(设置为private)
  • 判断定义的type是否过于泛化
    • 可写成class template
  • 判断是否真的需要定义新的type
    • 可写成新的drive class,non-member,templates以取代

条款20:宁以pass-by-reference-to-const替换pass-by-value

  • 尽量以pass-by-reference-to-const替换pass-by-value,效率高效,可以避免对象切割问题。
  • 对于内置类型,STL迭代器,和函数对象,"pass-by-value并不昂贵",采用pass-by-value更合适(其实采用pass-by-reference-to-const也可以)。

条款21:必须返回对象时,别妄想返回其reference

  • 不要返回pointer或者reference指向一个on stack对象

    • 局部对象被析构导致异常
  • 不要返回pointer或者reference指向一个on heap对象
    • 需要用户delete,可以选择返回shared_ptr
  • 不要返回pointer或者reference指向local static对象
    • static只能有一份,但可能返回多个对象
    • 确保只用一份时可以使用

      以上约束在必要时可以违背,非绝对。

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

  • 切记将成员变量申明为private
  • protected并不比public更有封装性(用户可能继承你的base class)

条款23:宁以non-member、non-friend替换member函数

  • 多一个成员函数,就多一分破坏封装性
  • 当non-member与member函数实现相同功能时,使用non-member函数
  • 尽量不要用友元

条款24:若所有参数皆需要类型转换,请为此采用non-member函数

  • 如果要求成员函数要对this指针所指的自身对象进行类型转换,那么只能将这个函数改为非成员函数
  • 其实质上是member函数没有办法转换this指针所指自身对象的类型
  • 也尽量不要用友元会破坏封装性的

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

  • std::swap调用copy构造函数和赋值操作符,效率较低,因此可以自己提供swap函数
namespace std {
template<typename T>
void swap(T& a, T& b) {
T temp(a);
a = b;
b = temp;
}
}
  • classes 可以提供一个member swap,再提供一个特化std::swap用来调用前者
#include <iostream>
#include <string>
#include <vector> class WidgetImpl {
public:
WidgetImpl( int _a, int _b, int _c, std::vector<double> _v) :
a(_a), b(_b), c(_c), v(_v) {}
int geta(){return a;}
private:
int a, b, c;
std::vector<double> v;
}; class Widget {
public:
Widget(WidgetImpl* _p) : pImpl(_p) {} Widget(const Widget& rhs) {
*pImpl = *(rhs.pImpl);
}
void swap(Widget& other) {
std::cerr << "member swap" << std::endl;
using std::swap;
swap(pImpl, other.pImpl);
}
WidgetImpl* getptr() {return pImpl;}
private:
WidgetImpl* pImpl;
}; namespace std {
template<>
void swap<Widget>(Widget& a, Widget& b) {
std::cerr << "std special swap" << std::endl;
a.swap(b);
}
} int main()
{
std::vector<double> v1(0.,10);
std::vector<double> v2(1.,10);
WidgetImpl a1(0,0,0,v1) , a2(1,1,1,v2);
Widget b1(&a1), b2(&a2);
std::swap(b1, b2);
std::cerr << b1.getptr()->geta() << std::endl;
}

  • classes 和 class templates 可以提供一个member swap,再提供一个non-member swap用来调用前者
#include <iostream>
#include <string> template<typename T>
class WidgetImpl {
public:
WidgetImpl(T _t, int _a, int _b, int _c, std::vector<double> _v) :
t(_t), a(_a), b(_b), c(_c), v(_v) {}
T getT(){return t;}
private:
T t;
int a, b, c;
std::vector<double> v;
}; template<typename T>
class Widget {
public:
Widget(WidgetImpl<T>* _p) : pImpl(_p) {} Widget(const Widget& rhs) {
*pImpl = *(rhs.pImpl);
}
void swap(Widget& other) {
std::cerr << "member swap" << std::endl;
using std::swap;
swap(pImpl, other.pImpl);
}
WidgetImpl<T>* getptr() {return pImpl;}
private:
WidgetImpl<T>* pImpl;
}; template<typename T>
void swap(Widget<T>& a, Widget<T>& b) {
std::cerr << "global swap" << std::endl;
a.swap(b);
} int main()
{
std::vector<double> v1(0.,10);
std::vector<double> v2(1.,10);
WidgetImpl<std::string> a1("str1", 0,0,0,v1) , a2("str2",1,1,1,v2);
Widget<std::string> b1(&a1), b2(&a2);
swap(b1, b2);
std::cerr << b1.getptr()->getT() << std::endl;
}

《Effective C++》设计与声明:条款18-条款25的更多相关文章

  1. Effective C++ ——设计与声明

    条款18:让接口更容易的被使用,不易误用 接口设计主要是给应用接口的人使用的,他们可能不是接口的设计者,这样作为接口的设计者就要对接口的定义更加易懂,让使用者不宜发生误用,例如对于一个时间类: cla ...

  2. Effective C++ —— 设计与声明(四)

    条款18 : 让接口容易被正确使用,不易被误用 欲开发一个“容易被正确使用,不容易被误用”的接口,首先必须考虑客户可能做出什么样的错误操作.  1. 明智而审慎地导入新类型对预防“接口被误用”有神奇疗 ...

  3. 《Effective C++》第4章 设计与声明(1)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  4. Effective C++笔记:设计与声明

    条款18:让接口容易被正确使用,不易被误用 1,好的接口很容易被正确使用,不容易被误用.你应该在你的所有接口中努力达成这些性质. 2,“促进正使用”的办法包括接口的一致性,以及与内置类型的行为兼容. ...

  5. Effective C++笔记04:设计与声明

    条款18:让接口easy被正确使用,不易被误用 1,好的接口非常easy被正确使用,不easy被误用.你应该在你的全部接口中努力达成这些性质. 2,"促进正使用"的办法包含接口的一 ...

  6. Effective C++笔记(四):设计与声明

    参考:http://www.cnblogs.com/ronny/p/3747186.html 条款18:让接口容易被正确使用,不易被误用 1,好的接口很容易被正确使用,不容易被误用.你应该在你的所有接 ...

  7. 《Effective C++》第4章 设计与声明(2)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  8. 【Effective C++】设计与声明

    条款18:让接口容易被正确使用,不易被误用 1,好的接口很容易被正确使用,不容易被误用.你应该在你的所有接口中努力达成这些性质. 2,“促进正使用”的办法包括接口的一致性,以及与内置类型的行为兼容. ...

  9. Effective C++阅读笔记 较详细 复杂条款带样例

    一.让自己习惯C++ 条款01:视C++为一个语言联邦 C++可视为: C:以C为基础. 面向对象的C++:添加面向对象特性. 模板C++:泛型编程概念,使用模板. STL:使用STL的容器.迭代器. ...

随机推荐

  1. Linux之系统优化

    查看系统版本 [root@luffy- /]# cat /etc/redhat-release CentOS release 6.9 (Final) [root@luffy- /]# uname -m ...

  2. Architecture of SQLite

    Introduction This document describes the architecture of the SQLite library. The information here is ...

  3. centos7下安装docker(15.6docker跨主机网络---Weave)

    Weave是weaveworks开发的容器网络解决方案.weave创建的虚拟网络可以将部署在多个主机上的容器连接起来.对于容器来说,weave就像一个巨大的网络交换机,容器可以直接通信,无需NAT和端 ...

  4. luogu P4735 最大异或和

    嘟嘟嘟 省选竟然考了一个可持久化trie,就挑着我不会的考. 话说考场上我确实写了一个trie的做法,只不过一直没调出来然后就只剩暴力分了. 现在想想实在是太蠢了,明明对算法没有把握,却头脑一热在这题 ...

  5. BAT美团滴滴java面试大纲(带答案版)之四:多线程Lock

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 这是多线程的第二篇. 多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸 ...

  6. P2690 接苹果(暴力搜索+记忆化)

    思路: 建树:就是在每一分钟进行分枝,是原地不动,还是移动.然后,走完整个过程. 但是,我其实还是走了弯路,因为,最开始想的是剪枝,没有用记忆化搜索.但是,肯定是能用dp来做,啊啊啊啊阿,能用dp肯定 ...

  7. 水题:P2799 国王的魔镜

    思路:简单模拟即可.判断一下是不是回文,是回文看长度是不是偶数.是偶数的话,说明又可能是回文.依次这样处理.但是只要长度为奇数则一定是原来的长度直接输出即可. #include<iostream ...

  8. angularjs处理/n转<br/>时候 <br/>不会解析的问题

    $scope.name=$sce.trustAsHtml($scope.name); <p ng-bind-html="name"></p>  

  9. VsCode云端版本

    VsCode的云端版与客户端简直是一模一样. 官网地址为:https://coder.com/ 安装命令: docker run -t -p 127.0.0.1:8443:8443 -v " ...

  10. 多线程爬虫爬取详情页HTML

    注意:如果想爬取详情页的信息请按须添加方法 import requests import os import re import threading from lxml import etree #爬 ...