感受到时间的宝贵

2016/9/2 珍惜 后悔

Posted by WangXiaoDong on September 2, 2016

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


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

    今天又是周五,感觉工作了以后每天怎么过的都这么快!可是还有好多知识都没有掌握,好多书都没有看!!
    时间真的是太宝贵了,哎,为什么以前我都没有珍惜呢?现在真的是非常后悔!!

总结一下今天工作中学到的要点:今天在工作中,主要遇到了一个事件相关的问题,就是我在编写一个Qt控件的时候,想要为这个控件增加一个事件处理!这里用到了Qt的事件处理模块。一般常用的按钮QPushButton控件本身就有单击事件,因此只要单击就会触发clicked信号,但是如果我想要给QLabel这种控件增加一个单击事件怎么办呢,这时就可以继承一下QLabel,然后为其内部实现mousePressEvent即可:

class new_qlabel : public QLabel
{
    Q_OBJECT
public:
    explicit new_qlabel(QWidget *parent = 0):QLabel(parent){}
protected:
    void mousePressEvent(QMouseEvent *e)
    {
        if(e->button() == Qt::MidButton)
        {
            qDebug()<<"点击了鼠标中键";
            emit on_midbutton_clicked();
        }
        QLabel::mousePressEvent(e);
    }

signals:
    on_midbutton_clicked();
};

为了简单,我实现文件和头文件写在了一起,实际编程时记着分开,这里要注意两点,一个是记着加Q_OBJECT宏,一个是处理完事件后运行父类的对应函数QLabel::mousePressEvent(e);从而将事件传递给父类,因为有些事件可能父类还要处理。

最后总结一下Qt事件处理提供的5个级别的事件处理和过滤:

  1. 重新实现事件函数。 比如: mousePressEvent(), keyPress-Event(), paintEvent() 。 这是最常规的事件处理方法。
  2. 重新实现QObject::event(). 这一般用在Qt没有提供该事件的处理函数时。也就是,我们增加新的事件时。这种方式常用于覆盖Tab键的默认意义。这种方式也可以用于处理那些没有特定事件处理器的不常见类型的事件中(如:QEvent::HoverEnter)。注意:重实现这个虚函数时记着结尾调用基类的event()函数,防止没有处理的事件止于此函数。
  3. 安装事件过滤器:对象使用installEventFilter()注册后,用于目标对象的所有事件都会首先发送给这个监视对象的eventFilter()函数。如果同一对象上安装多个事件处理器,那么按照安装顺序的逆序,即最近安装的到最先安装的,依次激活这些事件处理器。
  4. 在 QApplication 上安装事件过滤器。 这之所以被单独列出来是因为: QApplication 上的事件过滤器将捕获应用程序的所有事件,而且第一个获得该事件。也就是说事件在发送给其它任何一个eventFilter()函数之前发送给QApplication的eventFilter()函数。这种处理方式对于调试非常有用,也可用来处理那些发送给失效窗口部件的鼠标事件,因为QApplication通常会忽略这些事件。
  5. 重新实现QApplication 的 notify()方法. Qt使用 notify()来分发事件。要想在任何事件处理器捕获事件之前捕获事件,唯一的方法就是重新实现QApplication 的 notify()方法。

条款19:设计class犹如设计type

在 C++ 中,就像其它面向对象编程语言,可以通过定义一个新的类来定义一个新的类型。作为一个C++开发者,你的大量时间就这样花费在扩张你的类型系统。这意味着你不仅仅是一个类的设计者,而且是一个类型的设计者。重载函数和运算符,控制内存分配和回收,定义对象的初始化和终结过程——这些全在你的掌控之中。因此你应该在类设计中倾注大量心血,就如语言设计者在语言内置类型设计中所倾注的大量心血。

设计良好的类是有挑战性的,因为设计良好的类型是有挑战性的。良好的类型拥有简单自然的语法,符合直觉的语义,以及一个或更多高效的实现。那么,如何才能设计高效的类呢?首先,你必须理解你所面对的问题。实际上每一个类都需要你面对下面这些问题,其答案通常就导向你的设计规范:

  • 新类型的对象应该如何创建和销毁?如何做这些将影响到你的类的构造函数和析构函数,以及内存分配和回收函数(operator new,operator new[],operator delete,和 operator delete[])的设计,除非你不写它们。

  • 对象的初始化和对象的赋值应该有什么不同?这个问题的答案决定了你的构造函数和赋值运算符的行为以及它们之间的不同。

  • 值传递(passed by value)对于新类型的对象意味着什么?拷贝构造函数定义了一个新类型的传值如何实现。

  • 新类型的合法值是什么?通常,对于一个类的数据成员来说,仅有某些值的组合是合法的。那些数值集决定了你的类必须维护的约束条件。也决定了必须在成员函数内部进行的错误检查,特别是构造函数,赋值运算符,以及”setter”函数。它可能也会影响函数抛出的异常,以及(极少被使用的)函数异常明细(exceptionspecification)。

  • 你的新类型需要配合某个继承图系中?如果你从已经存在的类继承,你就受到那些类的设计约束,特别受到它们的函数是virtual还是non-virtual的影响。如果你希望允许其他类继承你的类,将影响到你是否将函数声明为virtual,特别是你的析构函数。

  • 你的新类型允许哪种类型转换?你的类型身处其它类型的海洋中,所以是否要在你的类型和其它类型之间有一些转换?如果你希望允许 T1 类型的对象隐式转型为 T2 类型的对象,你就要么在T1类中写一个类型转换函数(如operator T2),要么在 T2 类中写一个non-explicit-one argument构造函数。如果你只允许显示构造函数存在,就得写出专门负责执行转换的函数,且不得为类型转换操作符或non-explicit-oneargument构造函数。

  • 对于新类型哪些运算符和函数是合理的?这个问题的答案决定你为你的类声明哪些函数。其中一些是成员函数,另一些不是。

  • 哪些标准函数应该驳回?你需要将那些都声明为 private。

  • 你的新类型中哪些成员可以被访问?这个问题的可以帮助你决定哪些成员是 public,哪些是 protected,以及哪些是 private。它也可以帮助你决定哪些类 和/或 函数应该是友元,以及一个类嵌套在另一个类内部是否有意义。

  • 什么是新类型的未声明接口 “undeclaredinterface”?它对于效率,异常安全,以及资源使用(例如,多任务锁定和动态内存)提供哪种保证?你在这些领域提供的保证将为你的类的实现代码加上相应的约束条件。

  • 你的新类型有多大程度的通用性?也许你并非真的要定义一个新的类型,也许你要定义一整个类型家族。如果是这样,你就不该定义一个新的类,而应该定义一个新的类模板。

  • 一个新的类型真的是你所需要的吗?是否你可以仅仅定义一个新的继承类,以便让你可以为一个已有的类增加一些功能,也许通过简单地定义一个或更多非成员函数或模板能更好地达成你的目标。

类设计就是类型设计定义高效的类是有挑战性的。在C++中用户自定义类生成的类型最好可以和内建类型一样好。

请记住:

  • class的设计就是type的设计,在设计之前先要把上述问题过一遍,这样可以有把握设计一个成功的类。

今天设计模式的学习是两个原则,因此就没有专门的程序进行举例。

设计模式(四)————“开放–封闭原则”和“依赖倒转原则”

开放–封闭原则:软件实体(类、模块、函数等)应该可以扩展,但是不可以修改! 无论模块怎么封闭,都存在一些无法对之封闭的变化,因此设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化! 当变化发生时,我们就创建一个抽象来隔离以后发生的同类变化!!即:面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。 开放–封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分作出抽象,然而,对于应用程序中的每个部分刻意的进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。切记!切记!!

依赖倒转原则:抽象不应该依赖细节,细节应该依赖于抽象!即针对接口编程,不要对实现编程! 即: A.高层模块不应该依赖低层模块。两个都应该依赖抽象; B.抽象不应该依赖细节。细节应该依赖抽象。 依赖倒转其实是面向对象设计的标志,用哪种语言来编程不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都终止于抽象类或者接口,那就是面向对象的设计,反之那就是过程化的设计了!

里氏代换原则:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化。 即: 子类型必须能够替换掉它们的父类型。 只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能正真被复用,而子类也能够在父类的基础上增加新的行为。例如:

动物 animal = new 猫();   //需求变化,如将“猫”更换成“狗”,则后面都不需要改变!
animal.eat();
animal.drink();
animal.run();
animal.cry();