zoukankan      html  css  js  c++  java
  • effective c++ 笔记 (9-12)

    //---------------------------15/03/29----------------------------


    //#9    绝不在构造和析构过程中调头virtual函数

    {

       /*

            1:在构造时调用virtual函数有两个结果

                1>如果基类实现了这个函数,就调用基类的函数。

                2>基类没有实现这个函数,链接时报错。

                原因:

                1>基类的构造函数是早于 派生类的构造函数调用的,所以如果virtual函数使用派生类版本的

                话,很可能用到未初始化的派生类的成员变量。c++为了不让你走这条危险的路,就会只调用基类的版本

                2>根本原因:在调用基类构造函数时,对象类型是base class所以会调用基类版本。

                所以不要在构造函数中调用任何virtual函数。

            2:在析构函数中调用vitual函数:

                由于派生类的析构函数是先于基类调用的,所以轮到基类的构造函数时,派生类的成员变量依旧呈现

                未定义状态。所以c++视它们不存在,在调用基类析构函数时,对象称为一个base class对象。

            3:为了在派生类对象创建时,基类中有适当版本的显示信息调用,一个解决办法是由派生类传入一个消息,

            再调用non_virtual版本来显示。

         

         

         

        */

    }


    //#10   operator= 返回一个reference to *this

    {

       /*

            关于赋值,c++中可以写成连锁形式:

            int x,y,z;

            x = y = z = 15;

            为了实现这种连锁赋值,赋值操作符必须返回一个reference指向操作符的左侧实参。

                                                                            */

       class Widget

        {

        public:

            Widget&operator=(const Widget& rhs)

            {

                ...

               return *this;

            }

        };

    }


    //#11   operator=中处理自我赋值

    {

        //看下面的函数

        Widget&

        Widget::operator=(const Widget& rhs)

        {

           delete pb;

            pb =new Bitmap(*rhs.pb);

           return *this;

        }

        //这样如果是自我赋值,那就先deletepb,最后pb就指向一个已经删除的对象

        //如果让operator=具备异常安全性 往往自动获得自我赋值安全。

        Widget& Widget::operator=(const Widget& rhs)

        {

            Bitmap* pOrig = pb;

            pb =new Bitmap(*rhs.pb);

           delete pOrig;

           return *this;

        }

        //这么做会有效率问题:如果是自我赋值,那就多做了一次new以及delete;但是考虑到自我赋值的几率

        //并不建议在开头加上if判断来判断是否是自己。而且用了if语句,效率会明显下降

        //还有种方法是使用swap保证异常安全性

        Widget& Widget::operator=(const Widget& rhs)

        {

            Widget temp(rhs);

            swap(temp);

           return *this;

        }

        

    }


    //#12   复制对象时勿忘其每一个成分

    {

       /*

            1:当你自己实现operator=操作时,如果你忘记了一个成员变量的复制,编译器不会警告你

            2:当你写自己的operator=或者copy构造函数时应该记得:

                1>复制所有的自己的成员变量

                2>调用所有base classes内的适当的copying函数。

            3:如果发现copy构造函数和copy assignment操作符有相近的代码,消除重复代码的做法是

            建立一个init成员函数,供两者调用。(但是考虑到前面的条目,构造函数直接初始化效率会很高,所以

            如果相近的代码只是赋值的话,还是多动手的好)

         

        */

        PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)

        :Customer(rhs), priority(rhs.priority)

        {

            ...

        }

        

        PriorityCustomer&

        PriorityCustomer::operator=(const PriorityCustomer& rhs)

        {

            ...;

            Customer::operator=(rhs);

            prioriy = rhs.priority;

           return *this;

        }

    }












  • 相关阅读:
    LeetCode(287)Find the Duplicate Number
    LeetCode(290) Word Pattern
    LeetCode(205)Isomorphic Strings
    LeetCode(201) Bitwise AND of Numbers Range
    LeetCode(200) Number of Islands
    LeetCode(220) Contains Duplicate III
    LeetCode(219) Contains Duplicate II
    命令行执行Qt程序
    LeetCode(228) Summary Ranges
    redis 的安装和使用记录
  • 原文地址:https://www.cnblogs.com/boydfd/p/4983154.html
Copyright © 2011-2022 走看看