Смотрим предыдущий пример наследования указателя и пытаемся оставить все то же самое, но добавить наследование от QObject классов для использования технологии сигнал/слот.
main.cpp
class A
{
public:
A():ii( 111)
{
qDebug("ctor A ii : %i" , ii);
}
public:
int ii;
};
class AA: public A
{
public:
AA() : A()
{
ii = 222;
qDebug("ctor AA ii : %i" , ii);
}
};
class Dlg1: public QObject
{
Q_OBJECT
public:
Dlg1(QObject *parent=0) : QObject (parent)
{
qDebug("ctor Dlg1");
a = new A();
init();
}
A *a;
void init();
protected:
Dlg1(A* a_, QObject *parent ) : QObject(parent), a(a_) // important : dont remember a(a_)
{
qDebug("protected ctor Dlg1 ii : %i" , a->ii);
init();
}
signals:
void sig_1();
public slots:
void slot_1();
};
void Dlg1::init()
{
if ( ! connect(this , SIGNAL(sig_1()) , this , SLOT(slot_1())))
;
}
void Dlg1::slot_1()
{
qDebug("Dlg1::slot_1()");
}
class Dlg2: public Dlg1
{
//Q_OBJECT
public:
Dlg2(QObject *parent=0 ) : Dlg1( new AA() , parent) //
{
qDebug("ctor Dlg2 ii : %i" , a->ii);
}
void foo()
{
qDebug("foo ii : %i" , a->ii);
}
//AA *aa;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Dlg2 dlg2;
return a.exec();
}
....
Все реализуем в main.cpp и в этом ошибка: все собирается нормально, но не линкуется:
main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall Dlg1::metaObject(void)const " (?metaObject@Dlg1@@UBEPBUQMetaObject@@XZ)
Причина в том, что все классы надо разнести по самостоятельным единицам трансляции, то есть по отдельным h/cpp файлам.
класс А
#ifndef A_H
#define A_H
#include
class A: public QObject
{
Q_OBJECT
public:
A(QObject * parent = 0);
int ii;
void fooA();
signals:
void sig_A();
public slots:
void slot_A();
};
#endif // A_H
------------------------------------cpp --------------------------
#include "a.h"
#include
A::A(QObject * parent): QObject(parent),
ii( 111)
{
qDebug("ctor A ii : %i" , ii);
}
void A::slot_A()
{
qDebug("A::slot_A()");
}
void A::fooA()
{
qDebug("sig_A()");
emit sig_A();
}
класс АА
#ifndef AA_H
#define AA_H
#include
#include "a.h"
class AA : public A
{
Q_OBJECT
public:
AA(QObject * parent =0);
public slots:
void slot_A();
};
#endif // AA_H
-------------------------------------- cpp --------------------------------
#include "aa.h"
#include "a.h"
#include
AA::AA(QObject * parent) : A(parent)
{
ii = 222;
qDebug("ctor AA ii : %i" , ii);
}
void AA::slot_A()
{
qDebug("AA::slot_A()");
}
класс Dlg1
#ifndef DLG1_H
#define DLG1_H
#include <QObject>
class A;
class Dlg1 : public QObject
{
Q_OBJECT
public:
explicit Dlg1(QObject *parent=0);
A *a;
void init();
virtual ~Dlg1();
protected:
Dlg1(A* a_, QObject *parent );
signals:
public slots:
};
#endif // DLG1_H
------------------- cpp -----------------------------------------
#include "dlg1.h"
#include "a.h"
Dlg1::Dlg1(QObject *parent) : QObject(parent), a(0)
{
qDebug("ctor Dlg1");
a = new A();
init();
}
Dlg1::Dlg1(A* a_, QObject *parent ) : QObject(parent), a(a_) // important : dont remember a(a_)
{
qDebug("protected ctor Dlg1 ii : %i" , a->ii);
init();
}
void Dlg1::init()
{
qDebug("Dlg1::init()");
if ( ! connect(a , SIGNAL(sig_A()) , a , SLOT(slot_A())))
qDebug("sig_A: connect is wrong ");
else
qDebug("sig_A: connect is ok");
}
Dlg1::~Dlg1()
{
qDebug("~Dlg1()");
if(a != 0)
delete a;
}
....
класс Dlg2
#ifndef DLG2_H
#define DLG2_H
#include "dlg1.h"
class AA;
class Dlg2 : public Dlg1
{
Q_OBJECT
public:
explicit Dlg2( QObject *parent = 0);
~Dlg2();
signals:
public slots:
};
#endif // DLG2_H
-------------------- cpp -------------------------------
#include "dlg2.h"
#include "aa.h"
Dlg2::Dlg2(QObject *parent) : Dlg1( new AA() , parent)
{
qDebug("ctor Dlg2 ii : %i" , a->ii);
}
Dlg2::~Dlg2()
{
qDebug("~Dlg2()");
if(a != 0)
delete a;
a=0;
}
main.cpp
#include <QtCore/QCoreApplication>
#include <QString>
#include <QDebug>
#include <QObject>
#include "dlg2.h"
#include "a.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Dlg2 dlg2;
dlg2.a->fooA();
//return a.exec();
return 0;
}
вывод:
ctor A ii : 111
ctor AA ii : 222
protected ctor Dlg1 ii : 222
Dlg1::init()
Object::connect: No such signal Dlg1::sig_Dlg1() in dlg1.cpp:22
sig_A: connect is ok
ctor Dlg2 ii : 222
sig_A()
AA::slot_A()
~Dlg2()
~Dlg1()
Удобство в том сигнал sig_A всегда испускается один из класса предка A (который является агрегацией в классе Dlg1), а вот слот срабатывает в зависимости от класса с которым мы работаем либо Dlg1 либо Dlg2.
И вот скажите не является ли это наследованием агрегации ( или композиции как хотите)?
Ведь реально наследуется только класс Dlg2 от Dlg1 и AA от A. переменная a есть агрегация в Dlg1. А в результате, мы работаем нормально и Dlg2 и с Dlg1, то есть мы переопределяем slot_A в AA ?...
Чтобы это работало мы используем два конструктора в классе A (один защищенный, хотя это не принципиально).
Мы знаем, что вариант использования конструктора определяется в классе наследнике в вызове конструктора самого наследника. Поэтому мы можем этим играть.
Кстати говоря аналогичного поведения можно добиться и просто через виртуальные функции, то есть необязательно использовать сигнал/слот Qt.
Файлы для скачивания
*
тестим наследование агрегации (так сказать)