和姥姥通话

2016/9/11 难受

Posted by WangXiaoDong on September 11, 2016

时间:2016年9月11日 天气:小雨:umbrella:


Author:冬之晓:angry:
Email: 347916416@qq.com
MyAppearance: MyAppearance

    今天下了一天的雨,天气立刻就凉快了下来。记得刚来余姚的时候,感觉非常不
适应,天天都闷热,现在渐渐习惯了。今天早晨,和姥姥视频聊天,发现姥姥现在
说话越来越慢了,心里非常难受。真希望姥姥能好起来!

条款27:尽量少做转型动作

首先是C++提供的四种转型操作:

  1. const_cast:常量性的转除。

  2. dynamic_cast:安全的向derived class进行转型,可能会带来很高的开销

  3. reinterpret_cast:低级转型,例如可讲pointer转成int,不建议使用

  4. static_cast: 强迫隐式转换,例如int to const int,int to double, 但是const int 到 int 只有const_cast能做到。

在我们面前经常出现的一种使用情况是,像下面这样:

 class Window{
 public:
     virtual    void onResize(){...}
     ...
 };
 class SpecialWindow: public Window{
 public:
     virtual void onResize(){
         static_cast<Window>(*this),onResize();
         ...
     }
     ...
 }

但是实际上上面的副本不能如愿以偿的调用其基类部分的onResize(),其事实上调用的是SpecialWindow的基类部分的副本的的单独的onResize,实际上和SpecialWindow的resize没有什么关系。这时,如果SpecialWindow本身也尝试去修改SpecialWidnow的非基类部分的话,那么对象就会进入一种伤残的状态.其基类部分没有进行必要的修改,但是派生类单独的部分却经历了修改,这样对象就会进入一种伤残的状态.

其实调用基类的Resize的正确方法根本就不需要用到转型操作:

class SpecialWindow:public Window{
public:
    virtual void onResize(){
        Window::onResize(){
            .......
        }
        ...
    }
};

再论dynamic_cast,记住一般起调用带来的开销还是比较大的。而一般需要dynamic_cast的主要情况是,只拥有一个base class 指针的情况下,想要对derived class进行单独的处理。一般有两种方式可以替代dynamic_cast达到这种效果.

第一种方法是取一个容器并在里面存储,直接指向derived class对象的指针(往往是智能指针)。

typedef vector<shared_ptr<SpecialWindow>> VPSW;
VPSW windPtrs;
...
for(VPSW::iterator iter = windPtrs.begin(); 
    iter != windPtrs.end(); ++iter){
    iter->blink();
}

还有一种方法就是,将虚函数从derived class向上再延伸一层,这样,直接使用Base class 的指针,就可以调用derived class的函数。

记住,优秀的代码是很少使用转型操作的,应该尽可能的隔离转型操作。

请记住:

  • 如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_casts。如果有个设计需要转型动作,试着发展无需转型的替代设计。

  • 如果转型是必要的,试着将它隐藏于某个函数背后。客户随后可以调用该函数,而不需将转型放进他们自己的代码内。

  • 宁可使用C++风格的新式转型,少用C风格转型,因为前者很容易辨识出来,而且也比较有着分门别类的职掌。

设计模式(十三)————观察者模式

观察者模式,也叫做发步-订阅模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,

这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己 举一个公司工作的例子,例子中秘书和boss充当观察者,通知员工们开始工作的更新!

#ifndef OBSERVER
#define OBSERVER
#include <QtDebug>
#include <QString>
#include <QSharedPointer>
#include "subject.h"

class Observer
{
public:
//    Observer(){}
    Observer(QString name, Subject *sub):_name(name),_sub(QSharedPointer<Subject>(sub)){}
    virtual ~Observer(){}
    virtual void update()=0;
protected:
    QString _name;
    QSharedPointer<Subject> _sub;
};

class StockObserver final:public Observer
{
public:
    StockObserver(QString name, Subject *sub):Observer(name, sub){}
    void update() override
    {
        qDebug() <<_sub->getSubjectState()<<_name<<"关掉股票,开始工作!";
    }
};

class AnimationObserver final:public Observer
{
public:
    AnimationObserver(QString name, Subject *sub):Observer(name, sub){}
    void update() override
    {
        qDebug() <<_sub->getSubjectState()<<_name<<"关掉动漫,开始工作!";
    }
};
#endif // OBSERVER

#ifndef SUBJECT
#define SUBJECT
#include <QtDebug>
#include <QString>
#include <QList>

class Observer;
class Subject
{
public:
//    Subject(){}
    virtual ~Subject()
    {
#if 1
        qDeleteAll(_observers);
#else
        for(auto i:_observers)
        {            
            delete i;
        }
#endif
        _observers.clear();
    }
    virtual void Attach(Observer *observer) = 0;
    virtual void Detch(Observer *observer) = 0;
    virtual void Notify() = 0;
//    void setSubjectState(QString str){_action = str;}
    QString getSubjectState(){return _action;}
protected:
    QString _action;
    QList<Observer *> _observers;
};

class Boss:public Subject
{
public:
    Boss(){Subject::_action = QString::fromUtf8("I am boss!");}
    void Attach(Observer *observer) override
    {
        _observers.append(observer);
    }
    void Detch(Observer *observer) override
    {
        _observers.removeOne(observer);
        delete observer;
        observer = nullptr;
    }
    void Notify() override;  //override不能写在类外面!!
};

class Secretary:public Subject
{
public:
    Secretary(){Subject::_action = QString("I am secretary!");}   //子类为啥不能初始化父类的成员变量
    void Attach(Observer *observer) override
    {
        _observers.append(observer);
    }
    void Detch(Observer *observer) override
    {
        _observers.removeOne(observer);
        delete observer;
        observer = nullptr;
    }
    void Notify() override;  //override不能写在类外面!!
};

#endif // SUBJECT

#include "subject.h"
#include "observer.h"

void Boss::Notify()
{
    for( auto i:_observers)
    {
        i->update();
    }
}

void Secretary::Notify()
{
    for( auto i:_observers)
    {
        i->update();
    }
}

#include "observer.h"
#include "subject.h"

int main(int argc, char * argv[])
{
    Subject *st = new Secretary();
    Observer *a = new StockObserver("妈妈",st);
    Observer *b = new AnimationObserver("小东",st);
    st->Attach(a);
    st->Attach(b);
    st->Detch(b);
    st->Notify();

    return 0;
}

这个例子通过观察者员工们的状态,同时在构造观察者的时候可以设置观察者的状态,达到了观察者模式的效果。