QObject 和组合模式

QObject

QObject 是 Qt 库中许多重要类的基类,如 QEvent,QApplication 和 QWidget 等。我们会将任何从 QObject 类派生出的对象看做是一个 QObject 对象。它可以使用信号和槽与其他 QObject 通信。
每个 QObject 都可以有(至多)一个父 QObject,和任意数量的子 QObject 。每个 QObject 都有一条 QObjectList 的列表,里面存放的是各个子对象的指针。
每个 QObject 父对象都会管理自己的子对象。这就意味着,在调用父对象析构函数时也会调用子对象的析构函数。
给某个对象设置父对象,就会隐含地将此对象的指针添加到父对象的子对象列表中,例如:objA->setparent(objB);
如果随后再运行objA->setparent(objC);,那么 objA 的指针就会从 objB 的子对象列表中移除,然后添加到 objC 的子对象列表中。这一操作被称为重新父化

注意:
通常而言,没有父对象的 QObject 对象需要在程序栈区中进行定义,而那些有父对象的 QObject 则可以在堆区动态创建出来。原因:位于栈区的对象在超出作用域时,就会被销毁,而它的子对象也会随着销毁。

值和对象

C++ 类型可以分成两类:值类型和对象类型。
值类型的实例通常相对简单,占用相邻的内存空间,而且可以进行快速复制或者比较。值类型的例子有:int,char,QString,QDate 和 QVariant。
QVariant 是一种特殊的联合体类型,可保存所有可复制的内置类型和编程人员自定义的类型。

提示:
尽量不要在堆区创建 QList ,QString,QImage 或者其它和 QVariant 相关的类型。原因1:Qt已经为你完成了引用计数和内存管理。其它原因不明。

组合对象:父对象和子对象

组合模式的意图是通过将【部分——整体】的层次结构表示成树形结构,以便于使用较为简单的部分创建出复杂的对象。
在这里插入图片描述
这幅图主要功能的每一个矩形框都是一个组件,它可能是一个复合组件并拥有一定数量子组件,也可能其中的仅仅是一个单独的组件。最后通过组件对应的一个个枝叶就可以汇聚成一颗完整的树。
如果要表达这所大学的架构可以使用组合模式来对这所大学进行建模。树中的每一个节点使用下面的类的对象进行表示。

class OrgUnit : public QObject
{
public:
    QString GetName();
    double GetSalart();
private:
    QString name_;
    double salary_;
};

通过 QObject 的公有接口,可以构建一颗类似于树的表达方式来描述这所大学的组织结构,然后实例化一个 OrgUit 并调用 setParent 函数将其添加到合适对象的子对象列表中。

下面的函数用于计算学校对应部分的工资总和。

double OrgUnit::GetSalary()
{
    QList<OrgUnit*> childList = findChildren<OrgUnit*>();
    double salaryTotal(salary_);
    if (!childList.isEmpty()) {
        foreach (OrgUnit* ougPtr, childList)
            salaryTotal += ougPtr->GetSalary();
    }

    return salaryTotal;
}

可以从任意特定的节点调用 GetSalary 方法,返回的结果是以此节点为根的树所对应大学中相应部门的工资总和。例如:如果 ougPtr 指向 University,那么 GetSalary 会返回的是整个大学的总工资;如果指向的是 EnglishDpt ,那么 GetSalary 会返回的是英语系的总工资。

查找子对象

每个 QObject 都可以拥有任意数量的 QObject 子对象。这些子对象的地址会存在一个特殊的 QObject 指针容器内。QObject 有一个成员函数,可以返回一个指向父对象中全部子对象的指针列表。这个函数的原型是:

const QObjectList& QObject::chidren()const

QObject还提供两个函数

T QObject::findChild (const QString & name = QString()) const
//返回一个子对象
QList<T> QObject::findChildren(const QString & name = QString()) const
//该函数返回一个类型为T的子对象列表。

以下为一个演示

class Person : public QObject
{
public:
    explicit Person(QString name, QObject *parent = 0);
    virtual ~Person();
};

Person::Person(QString name, QObject *parent)
    :QObject(parent)
{
    setObjectName(name);
    cout << QString("Constructing Person: %1").arg(name)<< endl;
}

Person::~Person()
{
    cout << QString("Destroying Person: %1").arg(objectName()) <<endl;
}


void growBunch()
{
    qDebug("First we create a bunch of object.");

    QObject bunch;

    Person* mike = new Person("Mike",&bunch);
    Person* carol = new Person("Carol",&bunch);
    new Person("Greg",mike);
    new Person("Bobby",carol);

    Person* child = bunch.findChild<Person* >("Mike");
    cout << child << "\t" << mike << endl;

    Person* alice = new Person("Alice",&bunch);
    cout <<  &bunch << "\t" << alice->parent() << endl;

    bunch.dumpObjectTree();

    return ;
}

int main(int argc, char *argv[])
{
    growBunch();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值