Connecting (in an unusual way) signals to slots - c++

I've designed some construction like this:
template<class Ui_Class>
class Base_Dialog : virtual public QDialog, protected Ui_Class
{
protected:
QDialog* caller_;
public:
template<class Implementation>
Base_Dialog(Implementation*const & imp,QDialog *caller,QWidget* parent = nullptr);
};
template<class Ui_Class>
template<class Implementation>
Base_Dialog<Ui_Class>::Base_Dialog(Implementation*const& imp,QDialog *caller,QWidget* parent):
QDialog(parent),
caller_(caller)
{
setupUi(imp);
}
I'm using it like so:
class My_Class : public **Base_Dialog<Ui::My_Class>**
{
Q_OBJECT
public slots:
void display_me()
{/*THIS IS NOT GETTING CONNECTED*/
QMessageBox::warning(this,"Aha!","Aha!");
}
public:
explicit My_Class(QDialog* caller = nullptr,QWidget *parent = nullptr);
};
Line_Counter::Line_Counter(QDialog* caller,QWidget *parent) :
Base_Dialog(this,caller,parent)
{
//setupUi(this);//THIS WORKS BUT I'D RATHER CALL IT FROM Base_Dialog
}
this above construct is suppose to ease and simplify the way of inheriting from QDialog and from Ui class. And this works, except that when slots and signals are introduced in my class the base class for some reason doesn't see them (slots/signals). If I call setupUi in My_Class ctor everything works correctly but I'd prefer to call it in Base_Class. Is there a way to do it?

The constructor for lineCounter should be renamed to My_Class as well, am I right?
The reason for this behavior is that the meta object returned in constructor of Base_Dialog from virtual const QMetaObject * metaObject() const is meta-object for Base_Dialog, as at this stage it is not yet instance of My_Class instance. My_CLass overrides this virtual method (invisibly in Q_OBJECT macro) but only after My_Class constructor code starts to execute - means after Base_Dialog code is finished. Signals and slots internally use meta-objects while connecting, so it seems this way it will not work.
Summarizing - you cannot do it, because constructor of Base_Dialog doesn't know that My_Class instance is being created and therefore cannot have acces to any of it's contents.
Sometimes this problem can be bypassed using CRTP, but in this case I have no idea if it's aplicable. I would rather opt for doing it Qt's way - call setupUi from My_Class constructor.

Related

Get object instance class name with Qt's meta-object system

I have 3 classes:
class Being : public QObject {
Q_OBJECT
public:
explicit Being(QObject *parent = nullptr);
};
class Animal : public Being {
Q_OBJECT
public:
explicit Animal(QObject *parent = nullptr);
};
class Dog : public Animal {
Q_OBJECT
public:
explicit Dog(QObject *parent = nullptr);
};
Being's implementation is the following:
Being::Being(QObject *parent) : QObject(parent) {
qDebug() << staticMetaObject.className();
}
I have the following code:
Being *pBeing = new Being();
Being *pAnimal = new Animal();
Being *pDog = new Dog();
Question is: is there a way to implement Being's constructor so that I can have access to the actual instance that points to my Being base class so that the log of the above code will be:
Being
Animal
Dog
?
EDIT:
My intention is that I want to be able to have a Animal.txt, Being.txt and Doc.txt that will be processed inside the Being base class. And I need to know, based on the instance's type, whether I need to parse Animal.txt, Being.txt or Doc.txt to get more information.
Does Qt support this? Is there a mechanism I can use to achieve this using C++/Qt? If not, could there be any elegant compromise solution for this?
It is not possible in the constructor of Being because the enclosing object is not constructed yet, therefore metadata about it is not available. However, you can write the initialize method that should be called after the object construction, e.g. with print function:
class Being : public QObject {
Q_OBJECT
public:
explicit Being(QObject *parent = nullptr) { qDebug() << this->metaObject()->className(); } // this will always print "Being"
void initialize() { qDebug() << this->metaObject()->className(); } // this will print the actual class name
};
class Animal : public Being {
Q_OBJECT
public:
explicit Animal(QObject *parent = nullptr) { initialize(); } // you can already use this method in the constructor
};
TEST(xxx, yyy)
{
Being* being = new Being();
Being* animal = new Animal();
being->initialize();
animal->initialize(); // or you can call it later
}
In case initialize method is not good solution, you can always hack it through Being constructor: explicit Being(QString name, QObject* parent = nullptr; and then explicit Animal(QObject *parent = nullptr): Being("Animal") {}, but I think it is less elegant.
My intention is that I want to be able to have a Animal.txt, Being.txt and Doc.txt that will be processed inside the Being base class. And I need to know, based on the instance's type, whether I need to parse Animal.txt, Being.txt or Doc.txt to get more information.
Never let a base class know anything about its subclasses. Ever.
No matter how tempting it might look like, do no do it (even if you find out how).
A class might have hundreds of subclasses. Take for example QObject. Should QObject (or could it possible) know about your reimplementation of QMainWindow?
So, whatever the reason for this design decision is, change it!
Possible solutions
If the process algorithm of the text files is the same, regardless of the subclass, create a base class method to do the processing and call it from the subclasses.
If the algorithm depends on the subclass, make the method abstract, i.e. virtual and withouth implementation (=0), and let the implementation to the subclasses.

Using Qt5 new connect syntax with inheritance

I am trying to use the new connect syntax in some legacy code but came upon an architectural problem. So let's pretend I have a BaseReader class that looks like this :
class BaseReader : public QObject
{
Q_OBJECT
public:
BaseReader();
public slots:
virtual void read(const fstream& myStream);
}
Then let's say I have some children classes like this
class Reader1 : public BaseReader
{
Q_OBJECT
public:
BaseReader();
public slots:
virtual void read(const fstream& myStream);
}
Some of the read work is done in the base class, some in the child class. I have about 4 classes that are switched around at runtime. I have a connectReaders function that looks like this :
void connectReaders(BaseReader* currentReader)
{
connect(this, SIGNAL(mustRead(const fstream&)), currentReader, SLOT(read(const fstream&)));
}
Now it is my understanding that if I use the new syntax I will connect to the base member function no the overloaded versions. Is that correct ? Is there any way to connect these signals using the new syntax without modifying the architecture ? My example is very simplified and modifying that code would require a couple of months (including tests). It works the old way but I would like to take advantage of the new syntax. Any ideas ?
I have looked at these threads but they do not seem to offer a solution to this problem :
This is the other way around:
Using Qt signals and slots with multiple inheritance
I have read this but I am not sure I understand how the overload
section applies: https://wiki.qt.io/New_Signal_Slot_Syntax
I have qt5.4.1, Visual Studio 2013.
There's no problem when using the new 'connect' syntax with virtual slots and base class object pointers. You're specifying the object instance (e. g. currentReader), and the specific method to be called will be resolved using this object's virtual methods table.
Disclaimer: I am not familiar with Qt. The question here however, seems to be a C++ question.
When using a pointer-to-member to a virtual function in a base class, on a pointer/reference to a derived class, an override in the derived class will be called (if it exists).
class Base
{
public:
virtual void f()
{
std::cout << "Base\n";
}
};
class Derived : public Base
{
public:
virtual void f()
{
std::cout << "Derived\n";
}
};
int main()
{
void (Base::* pmf)() = &Base::f;
Derived d;
(d.*pmf)();
}
Will print "Derived", not "Base";
If a Qt signal calls your member function pointer with a derived object, the function override will therefore get called.

Virtual method misconception in C++

I am not experienced in OOP. I am developing an application using C++ and Qt. I have implemented 2 classes, base one and the one that inherits from it. Then I have added virtual methods for both and everything worked. But then I realized that I don't think it should... Here is the example:
This is my base class :
namespace Ui {
class CGenericProject;
}
class CGenericProject : public QDialog
{
Q_OBJECT
public:
explicit CGenericProject(QWidget *parent = 0);
~CGenericProject();
EMeasures_t type();
private:
Ui::CGenericProject *ui;
virtual void initPlot();
protected:
QCustomPlot* customPlot;
QVector<double> m_x;
QVector<double> m_y;
EMeasures_t m_type;
};
It has a virtual method called initPlot and it looks like this:
void CGenericProject::initPlot()
{
customPlot = ui->workPlot;
customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes );
customPlot->setFocusPolicy(Qt::ClickFocus);
customPlot->xAxis->setAutoTickStep(false);
customPlot->yAxis->setAutoTickStep(false);
customPlot->xAxis->setTickStep(100);
customPlot->yAxis->setTickStep(100);
customPlot->xAxis->setRange(0, 1000);
customPlot->yAxis->setRange(0, 1000);
}
And then i have a class that derives it:
class CEisProject : public CGenericProject
{
public:
CEisProject();
~CEisProject();
private:
virtual void initPlot();
void exampleEisMethod();
};
its initPlot is here:
void CEisProject::initPlot()
{
// give the axes some labels:
customPlot->xAxis->setLabel("Re [Ohm]");
customPlot->yAxis->setLabel("- Im [Ohm]");
customPlot->replot();
}
This is how i create the object:
CGenericProject* test = new CEisProject();
Now, when the initPlot() method is called, first the initPlot() from base class CGenericProject is called and then initPlot() from CEisProject is called. I wanted this functionality, where I can predefine some stuff in generic class and then add specific stuff in the childs.
But when I think of it, shouldn't initPlot() be calles exclusevily? I mean, shouldn't the method be called from base class or child class, instead of both, one after another? I have noticed this after reading this answer.
Constructors:
CGenericProject::CGenericProject(QWidget *parent) :
QDialog(parent),
ui(new Ui::CGenericProject)
{
ui->setupUi(this);
initPlot();
m_x.clear();
m_y.clear();
}
CEisProject::CEisProject()
{
m_type = EMeasures_t::eEIS;
initPlot();
}
You did not show the definition of the constructors, just their declaration. But I'm pretty sure the constructor definitions contain the answer to your question.
You may not be aware that the derived class constructor calls the base class constructor before directing virtual functions to the derived class. So a virtual function called in the base class construction (of an object which will soon be derived class) gets the base class definition of that virtual function.
Also, your constructor should be like:
// File .h
CEisProject(QWidget *parent = 0);
// File .cpp
CEisProject::CEisProject(QWidget *parent) : CGenericProject(parent)
{
...
}
or you won't be able to parent your derived widgets.

Why can not I call virtual function from base class slot Qt

Can someone explain to me why is the overridden method is not being called in base class slot, instead I have a base version of method:
class ThreadsDispatcher : public QObject
{
Q_OBJECT
public:
explicit ThreadsDispatcher(QObject *parent = 0);
virtual ~ThreadsDispatcher();
virtual void OnThreadFinished(IThreadable *pWorker);
public slots:
void slotThreadFinished(IThreadable *pWorker);
};
void ThreadsDispatcher::slotThreadFinished(IThreadable *pWorker)
{
OnThreadFinished(pWorker);
}
void ThreadsDispatcher::OnThreadFinished(IThreadable *pWorker)
{
qDebug << "Base method, class" << this->metaObject()->className();
}
A subclass:
class CommandsQueueDispatcher : public ThreadsDispatcher
{
Q_OBJECT
public:
explicit CommandsQueueDispatcher(CommandFactory* baseFactory, QObject *parent = 0);
~CommandsQueueDispatcher();
void OnThreadFinished(IThreadable *pWorker);
};
void CommandsQueueDispatcher::OnThreadFinished(IThreadable *pWorker)
{
qDebug << "Subclass method, class" << this->metaObject()->className();
}
After call OnThreadFinished in slot I get:
Base method, class ThreadsDispatcher
If I call method OnThreadFinished from another method, I get normal:
Subclass method, class CommandsQueueDispatcher
I have tried to connect in base class and subclass, but there no changes:
connect(pThreadWorker, SIGNAL(sigFinished(IThreadable*)), this, SLOT(slotThreadFinished(IThreadable*)));
But if I connect from another class, i.e. neither subclass, nor base class:
connect(pThreadWorker, SIGNAL(sigFinished(IThreadable*)), pWorker, SLOT(slotThreadFinished(IThreadable*)));
where I need to replace this with the variable ptr, I get a normal result.
Function where I connect:
bool ThreadsDispatcher::AddThread(IThreadable* pThreadWorker)
{
connect(pThreadWorker, SIGNAL(sigFinished(IThreadable*)), this, SLOT(slotThreadFinished(IThreadable*)));
}
I don't instantiate ThreadsDispatcher directly. I create the CommandsQueueDispatcher's object non-static.
A troubleshooting suggestion (too long for a comment):
Try changing the slot to be like this:
void ThreadsDispatcher::OnThreadFinished(IThreadable *pWorker)
{
qDebug << "Base method, class" << this->metaObject()->className();
}
And same for derived class. See what is output.
If output is "correct" in the sense that called virtual method is consistent with the class name, then I suspect you somehow do have a base class object, instead of derived class object.
If there's output mismatch, base class virtual method does the print but reports derived class name, then I'd look for any funny compiler flags, and try to create a SSCCE with a fresh project, then perhaps ask again here and/or file a bug report to Qt.
A link for starting to read about this in Qt docs.
A seconds step in troubleshooting: change the base class to be abstract, by making this method abstoract in base class:
virtual void OnThreadFinished(IThreadable *pWorker) = 0;
...and then remove the method definiton. Now compiler should tell you where you try to create an instance of base class.
One more suggestion: the Qt build basics, listed for example in this answer. In particular, make sure QObject subclasses are defined in .h files, which are listed in .pro file HEADERS list.

QT : Templated Q_OBJECT class

Is it possible to have a template class, which inherit from QObject (and has Q_OBJECT macro in it's declaration)?
I would like to create something like adapter for slots, which would do something, but the slot can take arbitrary number of arguments (number of arguments depends on the template argument).
I just tried doing it, and got linker errors. I guess gmake or moc is not getting called on this template class. Is there a way to do this? Maybe by explicitly instantiating templates?
It is not possible to mix template and Q_OBJECT but if you have a subset of types you can list the slots and signals like this:
class SignalsSlots : public QObject
{
Q_OBJECT
public:
explicit SignalsSlots(QObject *parent = 0) :
QObject(parent) {}
public slots:
virtual void writeAsync(int value) {}
virtual void writeAsync(float value) {}
virtual void writeAsync(double value) {}
virtual void writeAsync(bool state) {}
virtual void writeAsync(svga::SSlideSwitch::SwitchState state) {}
signals:
void readAsynkPolledChanged(int value);
void readAsynkPolledChanged(float value);
void readAsynkPolledChanged(double value);
void readAsynkPolledChanged(bool state);
void readAsynkPolledChanged(svga::SSlideSwitch::SwitchState state);
};
...
template <class T>
class Abstraction : public SignalsSlots
{...
Taking into account some restrictions: you can.
First please became familiar (if already not) https://doc.qt.io/archives/qq/qq16-dynamicqobject.html. - it will help to imlement it.
And about restrictions: you can have a template QObject class i.e. template class derived from QObject, but:
Do not tell the moc to compile it.
Q_OBJECT is just a macro and you have to replace it by it real
content which is virtual interface and something else :)
Implement QMetaObject activation (above mentioned virtual interface
and be caution with object info data, which is also come from
Q_OBJECT) and some else functionality and you will have template
QObject (even with template slots)
But as I managed to catch the one draw back - it is not possible to
simply use this class as a base for another class.
There are some other drawbacks - but I think the detail
investigation will show you them.
Hope this will helpful.
It is still not possible to mix templates and Q_OBJECT but depending on your use case you may use the new 'connect'-syntax. This allows at least the usage of template-slots.
Classical non-working approach:
class MySignalClass : public QObject {
Q_OBJECT
public:
signals:
void signal_valueChanged(int newValue);
};
template<class T>
class MySlotClass : public QObject {
Q_OBJECT
public slots:
void slot_setValue(const T& newValue){ /* Do sth. */}
};
Desired usage but not compilable:
MySignalClass a;
MySlotClass<int> b;
QObject::connect(&a, SIGNAL(signal_valueChanged(int)),
&b, SLOT(slot_setValue(int)));
Error: Template classes not supported by Q_OBJECT (For
MySlotClass).
Solution using new the 'connect'-syntax:
// Nothing changed here
class MySignalClass : public QObject {
Q_OBJECT
public:
signals:
void signal_valueChanged(int newValue);
};
// Removed Q_OBJECT and slots-keyword
template<class T>
class MySlotClass : public QObject { // Inheritance is still required
public:
void slot_setValue(const T& newValue){ /* Do sth. */}
};
Now we can instantiate desired 'MySlotClass'-objects and connect them to appropriate signal emitters.
MySignalClass a;
MySlotClass<int> b;
connect(&a, &MySignalClass::signal_valueChanged,
&b, &MySlotClass<int>::slot_setValue);
Conclusion: Using template-slots is possible. Emitting template signals is not working since a compiler error will occur due to missing Q_OBJECT.
I tried explicitly instantiating templates, and got this :
core_qta_qt_publisheradapter.hpp:96: Error: Template classes not supported by Q_OBJECT
I guess that answers my question.
EDIT
Actually, if I place whole template class definition in the header, then the qt preprocessor doesn't process it, and then I get linker errors. Therefore it must be possible to do it, if I add missing methods.
EDIT #2
This library did exactly what I wanted - to use a custom signal/slot mechanism, where the slot has not-defined signature.