zoukankan      html  css  js  c++  java
  • Effective C++


    author: lunar
    date: Mon 14 Sep 2020 07:12:16 PM CST

    5. 设计与声明

    条款20: Prefer pass-by-reference-to-const to pass-by-value

    缺省情况下C++会以传值形式作为函数参数, 但是这样会带来巨额的构造函数和析构函数的开销.

    所以在确定被调用函数不需要对参数进行修改时, 应该进行引用传值. 同时为了确保传参不会被改变, 应该使用const进行修饰.

    void func(const Student& s);
    

    不要使用传值方式的另一个原因是传参对于类信息的切割, 比如你写的一个函数接受某个base class作为参数, 那么其子类按道理来说都可以作为参数传入. 但是其子类所有的特征化信息都会被切除. 所以如果你需要在这个函数内调用的函数在子类有重载的话, 可能会失败.

    只有通过pass-by-reference-to-const才能解决这个问题.

    以上规则并不适用于内置类型, 以及STL的迭代器和函数对象. 对它们而言, pass-by-value更加适合.

    条款21: Don't try to return a reference when you must return an object.

    最重要的一点是在函数内创建的local对象位于栈区, 在函数退出后就会被销毁. 如果对该引用进行操作, 将会带来不明确行为.

    如果你说我可以通过new在堆区创建一个不会被自动销毁的对象, 那将会是一个更加糟糕的做法.

    因为这表示所消耗的资源需要自己回收, 这就使得用户在使用函数之后还要记得回收资源, 违背了接口设计的简洁易用的原则.

    更何况, 很多时候用户在使用接口时可能是将结果直接作为式中的一个元素进行运算, 都不会找个变量进行承接, 更别提进行回收了, 这绝对会造成资源泄露.

    如果将结果的reference指向一个static静态对象, 也有很多问题. 因为static对象是全局唯一的, 首先就带来了线程安全问题. 其次, static对象不会被多次创建, 导致多次调用函数返回的结果都指向同一个结果, 这可能并不是调用者希望看到的结果.

    所以, 尽管返回一个新对象会带来构造和析构成本, 但是与这些问题比起来是值得的.

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

    首先是一致性问题, 用户不需要考虑到底是直接调取成员变量还是通过成员函数来调用. 因为用户可以接触到的只有成员函数.

    其次是安全性考虑. 将成员变量隐藏在函数接口的背后, 可以为"所有可能的实现"提供弹性. 比如你要在用户每一次调用某个成员变量时打印一下日志, 如果你是直接暴露成员变量给客户, 那么这个操作很难实现. 如果是暴露接口的话, 那么可以加入很多自己希望的操作.

    条款23: Prefer non-member non-friend functions to member functions.

    假设网页浏览器类中存在一些成员函数, 分别用来清楚网页中的一些数据:

    class WebBrowser {
    public:
        ...
        void clearCache();
        void clearCookie();
        void clearHistory();
        ...
    };
    

    有的用户可能想一次执行所有操作:

    class WebBrowser {
    public:
        ...
        void clearEverything();
        ...
    };
    

    还有一种做法是另外设立一个函数, 依次执行该类的所有关于清楚数据的函数:

    void clearEverything(WebBrowser& web) {
        web.clearCache();
        web.clearCookie();
        web.clearHistory();
    }
    

    那么, 哪种做法更好呢?

    相信很多人都会认为第一种封装性更好, 应该选第一种.

    可事实是第二种做法带来的封装性更好. 封装的本质是为了让我们改变事务而影响更少的客户. 现在增加了clearEverything成员函数之后, 访问数据的函数增多了, 所以对于数据的封装性反而减少了.

    所以, 并不是把所有的东西都放在类里面就叫封装性好.

    所以你面临在成员函数和非成员函数之间做出选择的话, 就应该尽量选择非成员函数. 因为非成员函数不会带来任何对于成员变量的访问的风险.

    当然, 对于非友元函数和友元函数的抉择一样. 友元函数和成员函数一致, 两者对于类的封装性的冲击也是一致的.

    在C++中, 比较自然的做法是让clearEverything成为一个普通函数并与WebBrowser位于同一个namespace中.

    这样用户可以任意在namespace中添加便利函数而不影响任何封装性.

    条款24: Declare non-member functions when type conversions should apply to all parameters.

    因为隐式类型转换只会作用到运算符右边的参数, 左边的参数如果也需要进行类型转换的话就无法通过编译.

    我愿潇洒如鹰,远离地上宿命
  • 相关阅读:
    (13)使用Ajax Helper 提高用户体验
    (12)改变图片的大小生成缩略图
    (11)通过表单上传文件
    程序员需要有多懒 ?- cocos2d-x 数学函数、常用宏粗整理
    xCode 4.X 免证书真机发布及调试
    35岁前必须做好的10件事情(转载)
    独自收集Cocos2d提供的字体!共57种(有对照的字体图)
    (10)根据关键字搜索
    tcp拥塞控制
    dpcnv reademe
  • 原文地址:https://www.cnblogs.com/lunar-ubuntu/p/13669708.html
Copyright © 2011-2022 走看看