看动漫rewrite

2016/9/4 宅在家 看动漫

Posted by WangXiaoDong on September 4, 2016

时间:2016年9月4日 天气:晴:sunny:


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

有一天,我察觉到自己一无所有

发现本以为幸福满载的口袋之中,事实上空无一物

因为我从未付出过任何填补的努力,所以是理所当然的

可我却连这种事都想不明白

毕竟我的人生杂乱无章、空洞乏味

然而某一天

我突然深感自己正在失去大量的时间

我跟谁都说的上话。无论是怎样的人

可是我没有好朋友。一个都没有

这究竟意味着什么,我从未考虑过

我的人生,一直平淡乏味

——«rewrite»

    今天是周末,跟姥姥通话了。现在科技真是发达,以前从未想过有一天只要使用
网络,就可以免费和远在千里之外的家人视频对话,科技真的是太棒啦!

今天,主要看了一下Qt的容器,发现原来Qt的容器在进行操作的时候,既可以使用java的风格也可以使用C++的风格,同时还通过“引用计数”的方式实现了“写时复制”的功能。真的是太强大了。比如说遍历一个QList容器,可以使用如下两个风格的方式进行:

  • Java风格
 QList<int> ql;
    ql<<1<<2<<3;
    QListIterator<int> i(ql);
    while(i.hasNext())
        qDebug()<<i.next();
  • C++风格
    QList<int>::const_iterator j = ql.constBegin();
    while(j != ql.constEnd())
    {
        qDebug()<<*j;
        ++j;
    }

QVariant

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

当你理解条款20后,很可能出现一种过度使用的情况:只要看到是一个非内置类型,就去使用引用传值。例如:

class Rational
{
public:
       Rational(intnumerator=0,int denominator=1);   //条款24解释此函数为什么不声明为explicit
private:
       int n,d; //分子numerator和分母denominator
friend Rational operator*(constRational& lhs constRational& rhs);
};

这个版本operator*以by value返回结果(一个对象),看似要付出构造和析构成本,事实上是吗?如果改用返回引用,不需付出代价。但是,引用只是个名称,代表某个既有对象。任何时候看到引用声明式,我们就应想到是它的另一个名称是什么。operator*如果返回一个reference,则一定指向一个已有Rational对象,包含两个Rational对象乘积。如下代码:

Rational a(1,2);         //a=1/2;
Rational b(3,5);          //b=3/5;
Ratioanal c=a*b;        //c应为3/10

原本就存在“3/10”对象并不合理“,如果operator*要返回一个对象指向此数值,必须首先创建那个Ratioanl对象函数创建新对象的方法有二:在stack空间或在heap空间。根据这个策略写为operator*如下:

const Rational& operator*(constRational& lhs constRatioanl& rhs)
{
      Rationalresult(lhs.n*rhs.n,lhs.d*rhs.d);//糟糕代码
      returnresult;
}

采用此方法是为了避免返回对象的构造,事实上生成result时同样会调用构造函数。更重要的是返回的result是一个local对象,在函数退出前就被销毁了。事实上:任何函数如果返回一个reference指向某个local对象,都将一败涂地。(返回一个指针指向一个local对象同样如此)。既然在stack不可行,那我们考虑在heap内构造,并返回reference指向它(事实上同样不可行)

const Rational& operator*(constRational& lhs constRatioanl& rhs)
{
    Rational result=new Rational(lhs.n*rhs.n,lhs.d*rhs.d);//更糟糕的代码
    return*result;
}

因为分配内存以一个适当对象完成初始化动作,还是得调用构造函数。另外一个问题:谁将对new对象实施delete?即使有良好意识,但还是无法阻止内在泄漏,考虑如下代码:

Rational w,x,y,z;
w=x*y*z;    //等价于operator*(operator*(x,y),z)

调用两次operator*,两次new,但无法合法进行两次delete调用。因为没有合理办法取得operator*返回的reference的指针,必然导致资源泄漏。

一个“必须返回新对象”的函数的正确写法是(返回一个新对象):

inline const Rational operator*(constRational& lhs,const Rational& rhs)
{
    return Ratioanal(lhs.n*rhs.n,lhs.d*rhs.d);
}

承担operator*返回值的构造成本和析构成本,从长远来看只是为正确行为付出的一点个代价。 以上讨论总结为:当必须在“返回一个reference和返回一个Object”之间选择时,需要做的是挑出行为正确的那个。让编译器厂商为“尽可能降低成本”鞠躬尽瘁吧!

请记住:

  • 绝对不要返回pointer或reference指向一个local stack对象,指向一个heap-allocated对象也不是好方法,更不能指向一个local static对象(数组),该让编译器复制对象的时候,就让它去复制!

设计模式(六)————代理模式

代理模式:为其他对象提供一种代理以控制对这个对象的访问

比如可以做一个最求女孩的类,使用一个代理来追求的话就会是这样的代码:

#ifndef PERSUITGIRL
#define PERSUITGIRL

#include <QString>
#include <QObject>
#include <QtDebug>
//被追求者类
class schoolGirl:public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:
    explicit schoolGirl(QObject *parent = 0):_name("undefined"){}
    QString name() const
    {
        return _name;
    }
    void setName(const QString & name)
    {
        _name = name;
    }
signals:
    void nameChanged(const QString & name);
private:
    QString _name;
};
//定义接口:实际对象和代理的公共接口,这样实际对象需要使用的地方都可以用代理完成!
class GiveGiftInterface
{
public:
    virtual void GiveDolls()=0;
    virtual void GiveFlowers()=0;
    virtual void GiveChocolate()=0;
    virtual ~GiveGiftInterface(){}
};
//追求者类如下
class Pursuit final:public GiveGiftInterface
{
public:
    explicit Pursuit(schoolGirl *mm)
    {
        _mm = mm;
    }
    ~Pursuit(){delete _mm;}
    void GiveDolls() override
    {
        qDebug() <<_mm->name()<<"送你洋娃娃!";
    }
    void GiveFlowers() override
    {
        qDebug() <<_mm->name()<<"送你鲜花!";
    }
    void GiveChocolate() override
    {
        qDebug() <<_mm->name()<<"送你巧克力!";
    }
private:
    schoolGirl *_mm;
};
//代理类如下
class Proxy final:public GiveGiftInterface
{
public:
    explicit Proxy(schoolGirl *mm)
    {
        _gg = new Pursuit(mm);
    }
    ~Proxy()
    {
        delete _gg;
    }
    void GiveDolls() override
    {
        _gg->GiveDolls();
    }
    void GiveFlowers() override
    {
        _gg->GiveFlowers();
    }
    void GiveChocolate() override
    {
        _gg->GiveChocolate();
    }
private:
    Pursuit *_gg;
};

#endif // PERSUITGIRL

然后主函数可以这样进行测试:

#include "persuitgirl.h"

int main(int argc, char * argv[])
{
    schoolGirl *mm= new schoolGirl;
    mm->setName("美美");
    Proxy *daili = new Proxy(mm);
    daili->GiveDolls();
    daili->GiveChocolate();
    daili->GiveFlowers();
    qDebug() <<"测试完成!";
    return 0;
}

这样就是一个简单的代理模式的例子。根据上面的例子我们可以看出,实际上代理模式就是有两个类具有同样的接口,然后其中代理类包含另一个类的实例,代理的接口实际上是用那个类的实例的接口来实现的,这样就隐藏了正真实现这个接口的实例。这就是代理模式的精髓所在!