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

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.

Related

Alternatives to virtual index implementation in a model

So I have again encountered the limits of QObjects that cannot be mixed with templates (at least not directly). Basically I have a proxy model class that uses indexing to translate the source positions to local positions and back. The index can be implemented in number of ways, for now I need two versions, one using QHash and one using QVector. The interface of the index is common to both with only subtle differences regarding index manipulation. With templates this would be easy, I would make the class a template and then used specialization for these two cases.
However the model needs to be a QObject so instead it seems I would need to use polymorphism like so:
class IndexInterface;
class VectorIndex; //inherits IndexInterface
class HashIndex; //inherits IndexInterface
class ProxyModel : public QObject
{
Q_OBJECT
public:
enum IndexType { Vector, Hash };
explicit ProxyModel(IndexType indexType, QObject *parent = 0) :
QObject(parent),
index(indexType == Vector ? new VectorIndex : new HashIndex)
{
}
//...
private:
IndexInterface *index = nullptr;
};
I have couple of issues with this. First, it requires dynamic allocation of the index which I would like to get rid off. Second, because of the use of pointer to IndexInterace to dispatch the calls to the index no method of the index will ever be inlined (I have looked over dissasembled code to confirm this and tried various optimizations etc. to no avail).
What would be the alternatives to this design ideally without dynamic allocation of the index and without virtual calls to the index?
Make the index-type-specific class one of the base classes:
template <typename Index> class IndexHandler {
};
using VectorIndexHandler = IndexHandler<QVector>;
using HashIndexHandler = IndexHandler<QHash>;
class VectorIndexProxy : public QAbstractItemModel, VectorIndexHandler {
... // should be very small
};
class HashIndexProxy : public QAbstractItemModel, HashIndexHandler {
... // should be very small
};
Then instead of passing the index type to the constructor, use a factory function:
QAbstractItemModel * proxyFactory(IndexType indexType, QObject * parent = 0) {
switch (indexType) {
case Foo::Vector:
return new VectorIndexProxy(parent);
...
}
}
If you envision an interface broader or different than QAbstractItemModel, you'll need to write such a base class and derive from it in the concrete implementations, of course.
You could use CRTP if needed for IndexHandler to call directly into the derived class's methods, making it even smaller:
template <typename Index, typename Derived> class IndexHandler {
Derived * derived() { return static_cast<Derived*>(this); }
const Derived * derived() const; // as above
void foo() {
derived()->setObjectName("Yay");
}
};
class VectorIndexProxy :
public QAbstractItemModel,
public VectorIndexHandler<QVector, VectorIndexProxy>
{
... // should be very small
};
You can also "promote" methods from the base class to be Qt slots:
class VectorIndexProxy : ... {
#ifdef Q_MOC_RUN
Q_SLOT void foo();
#endif
};
See this question about having a base non-QObject class with signals and slots.
Finally, you could use the PIMPL idiom, and have a concrete implementation of a fixed type just like you desire. The factory would be invoked in the constructor and you'd be swapping in different PIMPLs for different indices. That's not as expensive as you think since all Qt classes already dynamically allocate a PIMPL, so you can piggy-back on that allocation by deriving your PIMPL from QObjectPrivate (#include <private/qobject_p.h>), and passing the instance of the PIMPL to the protected QObject(QObjectPrivate&). This pattern is omnipresent in Qt, so even though it's an implementation detail, it's not going away in Qt 5 at the very least. Here's a rough sketch:
// ProxyModel.cpp
#include <private/qobject_p.h>
class ProxyModelPrivate : public QObjectPrivate {
// Note: you don't need a q-pointer, QObjectData already provides it
// for you! CAVEAT: q-pointer is not valid until the QObject-derived-class's
// constructor has returned. This would be the case even if you passed
// the q-pointer explicitly, of course.
...
}; // base class
class VectorProxyModelPrivate : public ProxyModelPrivate { ... };
class ProxyModel : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(ProxyModel)
ProxyModel * pimpl(IndexType indexType) {
switch (indexType) {
case Vector: return new VectorProxyModelPrivate();
...
}
public:
enum IndexType { Vector, Hash };
explicit ProxyModel(IndexType indexType, QObject *parent = 0) :
QObject(*pimpl(IndexType), parent)
{}
};
If you were deriving from QAbstractItemModel, your PIMPL would derive from QAbstractItemModelPrivate, in the same fashion; this works for any QObject-deriving class in Qt!

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.

Getting around Qt's templating restrictions

I want to write a simple flexible ftp server in C++ that can be parametrized with a class to handle the user (check login and password, deliver files etc.) supplied on server initialization.
So I came up with this neat (so I thought) idea:
class FtpDelegate
{
public:
FtpDelegate() {}
virtual ~FtpDelegate() {}
virtual bool login(QString username, QString password) = 0;
// ...
};
class DummyDelegate : public FtpDelegate
{
public:
virtual bool login(QString username, QString password)
{
return true;
}
};
template<class Delegate>
class FtpServer : public QObject, Derived_from<Delegate, FtpDelegate>
{
Q_OBJECT
public:
explicit FtpServer(const QHostAddress &address = QHostAddress::Any,
quint16 port = 21,
QObject *parent = 0);
public slots:
void newConnection();
private:
QTcpServer *server;
QHostAddress address;
};
template <class Delegate>
void FtpServer<Delegate>::newConnection()
{
FtpDelegate *delegate = new Delegate();
new FtpConnection (delegate, server->nextPendingConnection(), address, this);
}
class FtpConnection : public QObject
{
Q_OBJECT
public:
explicit FtpConnection(FtpDelegate *delegate,
QTcpSocket *socket,
const QHostAddress &address,
QObject *parent = 0);
public slots:
void newDataConnection();
private:
QTcpSocket *socket;
QTcpServer *dataServer; // needed to transfer data to user
QTcpSocket *dataSocket;
};
// server initialization
FtpServer<DummyDelegate> ftpServer();
and then (you probably saw that coming) bam!
Error: Template classes not supported by Q_OBJECT
it is likely that there are other errors or misconceptions too as I am only starting to learn the C++ template mechanism (and Qt as well).
My question is: what is the best way to make it work without using ugly hacks like passing function pointers or needing to create a factory implementation for each concrete FtpDelegate's derived class. Maybe there's some clever design pattern I just can't see. Eventually I can rewrite the network mechanism to boost if it is the best option.
It is not possible to create a template Q_OBJECT class (see this and answers).
Instead of using static inheritance, you should use a run-time inheritance, and inject an object inheriting from FtpDelegate class.
It looks like the FtpServer is actually a factory creating connections. From your question, I do not see why it has to be Q_OBJECT class. So you may need to reconsider your design, and simplify that class.
what is the best way to make it work without using ugly hacks like passing function pointers or needing to create a factory implementation for each concrete FtpDelegate's derived class.
The best way may be to have a factory class, which creates instances of FtpDelegate type. But you have so many problems in the posted code, that it is not possible to tell more without knowing all gory details.

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.

Connecting (in an unusual way) signals to slots

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.