zoukankan      html  css  js  c++  java
  • effective c++ 笔记 (35-40)

    //---------------------------15/04/24----------------------------

    //#35   考虑virtual函数以外的其他选择

    {

    /*

        1:通常情况下对于有变动的东西,我们都会设计成virtual函数,然后由子类来继承,并重新实现,

          但是,由于这个惯性思维,成了弱点。因为我们这样就没有想过别的实现方法。

        2:Non-Virtual Interface来代替virtual函数。

            1>virtual函数设计成private,并使用别的public函数调用。这里有一个很关键的一点:

              private virtual函数能实现多态么?答案是肯定的。尽情地重定义吧。

            2>在调用virtual函数的前后可以加上一些自己的控制,比如上锁,记录等等一切你想做的。

            3>其实也不一定必须是private的,自己看情况定义吧。

        3:使用Strategy模式:

            1>当你需要virtual函数时,可以考虑存储一个仿函数对象,然后在一个public函数中调用这个

              仿函数。

            2>这个仿函数内部的操作不应该依赖于类的内部细节,不然还是乖乖用virtual函数来的好。

            3>这时你会发现,可以动态地改变要调用的函数,比如一个计算血量值的函数,可以一开始调用

              正常版本的,当角色中毒什么的,就换一个计算血量的函数。哇!cool

        

    */

    }


    //#36   绝不重新定义继承而来的non-virtual函数

    {

    /*

        前提:D public继承自 B

        先看两个准则(前面的条款已经将过的)

            1>适用于B对象的每一件事,也使用于D对象,因为每个D对象 isa B对象。

            2>D一定会继承Bnon-virtual函数的接口和实现。

        所以,如果我们重新定义了一个non-virtual函数:

            1>Dpublic方式继承B,那么当D有一个函数需要重新定义(不变性凌驾特异性),这个函数

              应该为virtual的而不是non-virtual的。

            2>如果这个函数不需要被重定义(特异性凌驾不变性),那么D久不需要重定义mf,而且它也

              不应该尝试这么做。

        所以结论是:不要重定义继承而来的non-virtual函数。

     

    */

    }


    //#37   绝不重定义继承而来的缺省参数值

    {


    //  1:看下这两个函数:

        class Shape

        {

        public:

            enum ShapeColor{Red, Green, Blue};

            virtual void draw(ShapeColor color = Red) const = 0;

        };

        class Rectangle : public Shape

        {

        public:

            virtual void draw(ShapeColor color = Green) const;

        };

    /*

            这么做的结果就是:当客户使用基类指针,子类对象时,调用的内容是子类的,默认参数确实基类的。

            这样子做没有意义,所以问题朝着两个方向发展:

                1>你想切换默认参数。

                2>你想保留默认参数,但是切换调用的内容。如果子类也要使用相同的参数,那么如果默认参数一改变

                  基类和子类的都必须改变,所以这很糟糕。

            实现起来很简单嘛:

                1>想切换参数?定义一个non-virtual函数,然后用virtual的函数调用之,

                  调用时传入不同的参数就ok了。

                2>想切换调用内容?定义一个private virtual函数,然后用带着默认参数的non-virtual函数调用之。

     

    */

    }


    //#38   通过复合塑膜出has-a"根据某物实现出"

    {

    /*

        复合有两种情况:

            1>has-a

                如果你塑造的对象是世界中的某些事物,比如人、物、汽车等等,那么这样的对象属于应用域,

                当复合发生在应用域时,表现出has-a的关系。

            2>is-implemented-in-terms-of(根据某物实现出)

                如果你塑造的对象是为了实现细节上的人工制品,像缓冲区、互斥锁等,这样的对象属于实现域

                这样的复合表现出is-implemented-in-terms-of关系。

                具体的例子就是,当你想要实现一个set时,你可能需要在类内含一个std::list,因为你不想

                自己写list,这样的关系就是is-implemented-in-terms-of,这个set是根据list实现的

                这里不用继承的原因是:set不是一个listlist能用的地方set不一定能用。比如list可以插入

                重复的值而set不行。

    */

    }


    //#39   明智而审慎地使用private继承

    {

    /*

        1:private继承意味着is-implemented-in-terms-of。也就是和复合有着异曲同工之妙,然而哪个更好呢?

            1>复合可以防止virtual函数被重定义。

            2>复合可以解耦两个类,减少编译依赖性。

            3>private继承可以实现EBO,也就是使一个空的基类真的不占内存。

            4>private可以访问到基类protected的内容,复合不行。

        2:最后得出的结论:

            1>首先考虑复合。

            2>真的无法用复合实现,或者真的看重那4byte的字节,那就换成private吧。

    */

    }


    //#40   明智而审慎地使用多重继承

    {

    /*

        1:多继承常常有很多缺点:

            1>比单一继承复杂,可能会造成歧义性,也就是继承的两个基类中有相同名字的函数,那么单单使用

              函数名是不知道调用哪一个的。

            2>要求基类都来自virtual继承,可是virtual继承是以增加体积,减慢速度,以及复杂的初始化

              为成本实现的如果virtual base classes不带任何数据,将是最具使用价值的情况。

              (ps:都不带数据了,我不是virtual继承有影响么?就算不是virtual继承也不会有重复东西了啊,

              最多就是一个virtual指针)

        2:多重继承正当的用途:设计模式中的适配器模式

            但是这也是可以转变为复合方式来实现的,所以你需要明智而审慎地决定是否适用多重继承(ps:不建议使用)

    */

    }


  • 相关阅读:
    POJ 2996 Help Me with the Game (模拟)
    PCL系列——怎样逐渐地配准一对点云
    sublime text3同时编辑多行
    博客搬家
    将博客搬至CSDN
    centos7用xshell可以连接, xftp连接失败!(墙裂推荐)
    重启ssh服务出现Redirecting to /bin/systemctl restart sshd.service
    重装wordpress
    ubuntu 16.04 启用root用户方法
    Ubuntu创建新用户并增加管理员权限(授权有问题)
  • 原文地址:https://www.cnblogs.com/boydfd/p/4983126.html
Copyright © 2011-2022 走看看