Object members not retrieved from a Qt dll - c++

I try to get a QObject-subclassed object from a Qt shared library to a Qt application dynamically.
I have tried to apply a previous answer about this subject : QLibrary - import a class
Here is my common interface tabappinterface.h:
#ifndef TABAPP_H
#define TABAPP_H
#include <QObject>
#include <QWidget>
class TabAppInterface : public QObject
{
Q_OBJECT
public:
virtual ~TabAppInterface()
{
}
QWidget *app;
QString title;
};
#endif // TABAPP_H
My class dll-side mytabapp.h:
#ifndef MYTAB_H
#define MYTAB_H
#include "tabapp_global.h"
#include "tabappinterface.h"
class MYTABSHARED_EXPORT MyTabApp: public TabAppInterface
{
public:
MyTabApp();
virtual ~MyTabApp();
QWidget *app;
QString title;
};
extern "C" MYTABSHARED_EXPORT TabAppInterface *getTabApp();
and its implementation mytabapp.cpp:
#include "mytabapp.h"
MyTabApp::MyTabApp()
{
app = new AppWidget();
title = QStringLiteral("My Tab App");
}
MyTabApp::~MyTabApp()
{
}
TabAppInterface *getTabApp()
{
return new MyTabApp();
}
My app-side implementation:
void ContainerMainWindow::loadLibraries()
{
QLibrary myLib("mytabapp.dll");
if(myLib.isLoaded())
{
qDebug() << "Loaded!";
}
typedef TabAppInterface *(*tabAppGetProt)();
auto tabAppGetter = (tabAppGetProt) myLib.resolve("getTabApp");
if(tabAppGetter)
{
auto *tabApp = tabAppGetter(); // not null
qDebug() << tabApp->title; // print empty string
qDebug() << (QWidget *)(tabApp->app); // SEGFAULT
}
}
As stated in comment in the last lines, the object members are not retrieved although tabApp is not null.
Any idea?
Thanks!

You're accessing the base class variables (fields) title and app, which nobody ever initialized. These variables aren't virtual at all, so those in the derived class just hide those in the base class. As a solution, you can declare them as protected in the base class and encapsulate them in getters and setters.
This way, your base class is like:
class TabAppInterface : public QObject
{
Q_OBJECT
public:
virtual ~TabAppInterface(){}
QWidget *getApp() const { return app; }
void setApp(QWidget *value) { app = value; }
QString getTitle() const { return title; }
void setTitle(const QString &value) { title = value; }
protected:
QWidget *app;
QString title;
};
and the derived class is just like:
class MYTABSHARED_EXPORT MyTabApp: public TabAppInterface
{
public:
MyTabApp();
virtual ~MyTabApp();
};
You can still directly access the variables inside the derived class (i.e. initialize them in constructor) and through the getters/setters methods from outside:
auto *tabApp = tabAppGetter();
qDebug() << tabApp->getTitle();
qDebug() << tabApp->getApp();

Related

"Static polymorphism with Qt signal/slot: What is wrong?"

I'm trying to use static polymorphism instead of dynamics polymorphism with Qt signal/slot mechanism. But I get compile error. What is wrong in my code? What is workaround?
devices.h
#ifndef DEVICES_H
#define DEVICES_H
#include <QtCore>
#include <qdebug.h>
class DeviceController : public QObject
{
Q_OBJECT
public:
explicit DeviceController(QObject *parent = nullptr):QObject(parent){}
virtual ~DeviceController() {}
void doAllDevicesInit(){
emit deviceAInitSignal();
}
signals:
void deviceAInitSignal();
};
template<typename T> class BaseDevice {
public:
void init() {
static_cast<T*>(this)->doInit();
qDebug() << QString("BaseDevice initialized!");
}
};
class DeviceA : public BaseDevice<DeviceA> {
public:
void doInit() {
qDebug() << "DeviceA initialized!";
}
};
#endif // DEVICES_H
main.cpp
#include "devices.h"
int main(int argc, char *argv[])
{
Q_UNUSED(argc);Q_UNUSED(argv);
DeviceA deviceA;
DeviceController deviceController;
QObject::connect(&deviceController,&DeviceController::deviceAInitSignal,
&deviceA, &DeviceA::init);
deviceController.doAllDevicesInit();
return 0;
}
Compile output
Qt5.12.2/5.12.2/gcc_64/include/QtCore/qobjectdefs_impl.h:414:94:
error: invalid static_cast from type ‘QObject*’ to type
‘QtPrivate::FunctionPointer::*)()>::Object*’
{aka ‘BaseDevice*’}
FuncType::template call(static_cast(this_)->function, static_cast(r), a);
Thanks to drescherjm comment, a workaround is as follow
devices.h
...
template<typename T>
class BaseDevice: public QObject {
//Q_OBJECT, Error: Template classes not supported by Q_OBJECT
public:
explicit BaseDevice(QObject *parent = nullptr):QObject(parent){}
virtual ~BaseDevice() {}
void init() {
static_cast<T*>(this)->doInit();
qDebug() << QString("BaseDevice initialized!");
}
};
class DeviceA : public BaseDevice<DeviceA> {
Q_OBJECT
public:
explicit DeviceA(QObject *parent = nullptr):BaseDevice<DeviceA>(parent){}
virtual ~DeviceA() {}
void doInit() {
qDebug() << "DeviceA initialized!";
}
};
#endif // DEVICES_H

inheritance in Qt won't allow me to reference?

So I I have an h file and a cpp file in a Qt project. I have to declare some qstrings inside my header file and I would like to reference them in my cpp file but I don't seem to be able to access it, can someone explain why or the correct way to do it?
#ifndef PROFILE_H
#define PROFILE_H
#include <QMainWindow>
#include "login.h"
#include "searchnote.h"
#include "note.h"
#include <QDebug>
namespace Ui {
class Profile;
}
class Profile : public QMainWindow
{
Q_OBJECT
public:
explicit Profile(QWidget *parent = 0);
~Profile();
private slots:
void on_actionAdd_Note_triggered();
private:
Ui::Profile *ui;
private:
QString name;
QString major;
QString school;
Note myNoteList;
};
#endif // PROFILE_H
#include "profile.h"
#include "ui_profile.h"
Profile::Profile(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Profile)
{
ui->setupUi(this);
}
Profile::~Profile()
{
delete ui;
}
void Profile::on_actionAdd_Note_triggered()
{
SearchNote openSearch; //will send us the searchNote gui
openSearch.setModal(true);
openSearch.exec();
}
void myNoteListAdd(QString newName){
myNoteList.add(); //the cpp file doesnt recognize this object
}
myNoteListAdd is a stand-alone function, myNoteList is a private data member of Profile class.
Only member functions (often also called methods) of the same class can access these private data members
It may be the case that you intend myNoteListAdd to be a member function of Profile, i.e.
class Profile : public QMainWindow
{
Q_OBJECT
public:
explicit Profile(QWidget *parent = 0);
~Profile();
private slots:
void on_actionAdd_Note_triggered();
**void myNoteListAdd(QString newName);**
private:
Ui::Profile *ui;
private:
QString name;
QString major;
QString school;
Note myNoteList;
};
And implement as:
void Profile::myNoteListAdd(QString newName){
myNoteList.add(newName); // assuming you want to add newName to myNoteList
}
Otherwise, you need some form of accessing the member myNoteList, either by making it public or having a getter member. In either case you need an instance of a Profile to work with, i.e.:
class Profile : public QMainWindow
{
Q_OBJECT
public:
explicit Profile(QWidget *parent = 0);
~Profile();
//either this:
Note myPublicNoteList;
// or this
Note getNoteList() { return myNoteList; }
private slots:
void on_actionAdd_Note_triggered();
private:
Ui::Profile *ui;
private:
QString name;
QString major;
QString school;
};
then in your .cpp
void myNoteListAdd(QString newName)
{
Profile p = new Profile(); // or some other mechanism to get a Profile
//then either
p.myPublicNoteList.add(newName);
// or
p->getNoteList().add(newName);
}

How to access a struct from another another C++ class?

Hello I have a struct in a TreeItem class:
// TreeItem.h
class TreeItem
{
public:
struct TreePair
{
QString sa_key;
QVariant sa_value;
};
//... blabla
}
I would like access that struct TreePair from another class TreeModel , which has class TreeItem already formarded in its header:
// TreeModel.h
class TreeItem;
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
//..
}
// TreeModel.cpp
TreeModel::TreeModel(const QStringList &headers, const QString &data, QObject *parent)
: QAbstractItemModel(parent)
{
QVector<TreePair> rootData; // TreePair was not declared in this scope
}
My strcut was not declared in this scope?? In every class it was already automatically set like
#ifndef _TREEITEM_H
#define _TREEITEM_H
#endif
Since TreePair is nested inside TreeItem, it needs to be
QVector<TreeItem::TreePair> rootData;

Can't declare Q_ENUM from an enum defined in another class

This documentation states
If you want to register an enum that is declared in another class, the enum must be fully qualified with the name of the class defining it. In addition, the class defining the enum has to inherit QObject as well as declare the enum using Q_ENUMS().
However I can't make this work, in the following example.
Class A:
#ifndef CLASSA_H
#define CLASSA_H
#include <classb.h>
class ClassA : public QObject
{
Q_OBJECT
Q_ENUMS(ClassB::TestEnum)
public:
explicit ClassA(QObject *parent = 0) : QObject(parent)
{
const QMetaObject *metaObj = this->metaObject();
qDebug() << metaObj->enumeratorCount();
}
};
#endif // CLASSA_H
ClassB:
#ifndef CLASSB_H
#define CLASSB_H
#include <QDebug>
#include <QMetaEnum>
#include <QObject>
class ClassB : public QObject
{
Q_OBJECT
Q_ENUMS(TestEnum)
public:
enum TestEnum { A, B, C };
explicit ClassB(QObject *parent = 0) : QObject(parent)
{
const QMetaObject *metaObj = this->metaObject();
qDebug() << metaObj->enumeratorCount();
}
};
#endif // CLASSB_H
main:
#include <classa.h>
#include <classb.h>
int main()
{
ClassA objectA;
ClassB objectB;
}
Expected output:
1
1
Actual Output:
0
1
Here is a summary of a little research:
Information stated in the documentation about registration of a enum declared in another class looks outdated.
Q_ENUMS(Class::EnumName doesn't create a new enumerator, and useless.
When you declare a new Q_PROPERTY in ClassA you should use full form of the enum ClassB::EnumName.
As soon as EnumName is registered in ClassB it doesn't need to be registered any more.
A property created using a enumerator from another class works correctly.
class ClassA : public QObject
{
public:
Q_OBJECT
Q_PROPERTY(ClassB::TestEnum test READ test)
public:
explicit ClassA(QObject *parent = 0)
{
const QMetaObject *metaObj = this->metaObject();
qDebug() << metaObj->enumeratorCount();
QMetaProperty property = metaObj->property(metaObj->indexOfProperty("test"));
if (property.isEnumType())
{
const QMetaEnum& enumerator = property.enumerator();
qDebug() << enumerator.name();
for (int i = 0 ; i < enumerator.keyCount(); i++)
{
qDebug() << QLatin1String(enumerator.key(i)) << enumerator.value(i);
}
}
}
ClassB::TestEnum test() const
{
return ClassB::A;
}
};
Output:
0
TestEnum
"A" 0
"B" 1
"C" 2

Calling function from (Qt) plugin fails

I want to write an application which consists of several plugins. My idea is that the plugin itself is always just a factory which then can create the required object.
So I created an Interface for the pluginfactory called AbstractFactoryPlugin with a pure virtual method called create. Because of the fact that I want to have several different plugins (factories) with the same interface I can’t put the Q_DECLARE_INTERFACE macro in the AbstractFactoryPlugin header file.
So for a sample plugin I created an Interface which inherits from AbstractFactoryPlugin called IMyObjectFactoryPlugin and declared this interface with the DECLARE macro. Further the MyObjectFactoryPlugin then inherits from QObject and IMyObjectFactoryPlugin.
But when I load the plugin and call the create function, the create function of MyObjectFactoryPlugin seems to be never called. What am I doing wrong?
Many thanx in advance.
Sourcecode:
#ifndef ABSTRACTPLUGINFACTORY_H
#define ABSTRACTPLUGINFACTORY_H
#include "IAnObject.h"
class AbstractFactoryPlugin
{
public:
virtual ~AbstractFactoryPlugin() {}
virtual IAnObject *create(QObject *parent) = 0;
};
#endif // ABSTRACTPLUGINFACTORY_H
#ifndef IMYOBJECTFACTORYPLUGIN_H
#define IMYOBJECTFACTORYPLUGIN_H
#include "AbstractFactoryPlugin.h"
#include <QtPlugin>
class IMyObjectFactoryPlugin : public AbstractFactoryPlugin
{
public:
virtual ~IMyObjectFactoryPlugin() {}
};
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(IMyObjectFactoryPlugin,
"org.MyObjectFactoryPlugin");
QT_END_NAMESPACE
#endif // IMYOBJECTFACTORYPLUGIN_H
#ifndef MYOBJECTPLUGIN_H
#define MYOBJECTPLUGIN_H
#include <QtPlugin>
#include "IMyObjectFactoryPlugin.h"
#include "AbstractFactoryPlugin.h"
class MyObjectFactoryPlugin : public QObject, IMyObjectFactoryPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.MyObjectFactoryPlugin" )
Q_INTERFACES(IMyObjectFactoryPlugin)
public:
MyObjectFactoryPlugin(QObject *parent = 0);
IAnObject *create(QObject *parent);
};
#endif // MYOBJECTPLUGIN_H
#include "MyObject.h"
#include "MyObjectFactoryPlugin.h"
#include <QDebug>
MyObjectFactoryPlugin::MyObjectFactoryPlugin(QObject *parent) :
QObject(parent)
{
}
IAnObject *MyObjectFactoryPlugin::create(QObject *parent)
{
qDebug() << Q_FUNC_INFO << "was called";
return new MyObject();
}
#ifndef IANOBJECT_H
#define IANOBJECT_H
class IAnObject
{
public:
IAnObject() {isInitialized = false;}
virtual ~IAnObject() {}
virtual bool initialize() = 0;
protected:
bool isInitialized;
};
#endif // IANOBJECT_H
#include "IAnObject.h"
#ifndef MYOBJECT_H
#define MYOBJECT_H
class MyObject : public IAnObject
{
public:
MyObject();
bool initialize();
};
#endif // MYOBJECT_H
#include "MyObject.h"
MyObject::MyObject()
{
}
bool MyObject::initialize()
{
return true;
}
#include <QCoreApplication>
#include <QDir>
#include <QPluginLoader>
#include <QDebug>
#include <E:/QtProjects/_test_PlugIn/MyPlugin/AbstractFactoryPlugin.h>
#include <E:/QtProjects/_test_PlugIn/MyPlugin/IAnObject.h>
#include <E:/QtProjects/_test_PlugIn/MyPlugin/IMyObjectFactoryPlugin.h>
IAnObject *loadPlugin()
{
QDir dir(QCoreApplication::applicationDirPath());
qDebug() << dir;
foreach(QString fileName, dir.entryList(QDir::Files))
{
QPluginLoader pluginLoader(dir.absoluteFilePath(fileName));
QObject *plugin = pluginLoader.instance();
qDebug() << fileName;
if(plugin)
{
qDebug() << "##### Plugin load ok #####";
AbstractFactoryPlugin *abstractFactoryPlugin = reinterpret_cast<AbstractFactoryPlugin *>(plugin);
return abstractFactoryPlugin->create(NULL);
}
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "loadPlugin:" << loadPlugin();
return a.exec();
}
Any Qt5 plugin must inherit from QObject, if you want your base class to be independent from QObject you'll have to create an intermediary class that inherits both AbstractFactoryPlugin and QObject (let's call it AbstractMyObjectFactoryPlugin).
#ifndef ABSTRACTMYOBJECTFACTORYPLUGIN_H
#define ABSTRACTMYOBJECTFACTORYPLUGIN_H
#include "AbstractFactoryPlugin.h"
class AbstractMyObjectFactoryPlugin : public QObject, public AbstractFactoryPlugin
{
Q_OBJECT
public:
AbstractMyObjectFactoryPlugin(QObject *parent = 0) : QObject(parent) { }
virtual ~AbstractMyObjectFactoryPlugin() { }
};
Q_DECLARE_INTERFACE(AbstractMyObjectFactoryPlugin,
"org.AbstractFactoryPlugin");
#endif // ABSTRACTMYOBJECTFACTORYPLUGIN_H
To create a plugin, you'll have to inherit from this class and override the create() method:
class MyObjectFactoryPlugin : public AbstractMyObjectFactoryPlugin
{
Q_OBJECT
Q_INTERFACES(AbstractMyObjectFactoryPlugin)
Q_PLUGIN_METADATA(IID "org.MyObjectFactoryPlugin" FILE "MyObjectFactoryPlugin.json")
public:
MyObjectFactoryPlugin(QObject* parent = 0) : AbstractMyObjectFactoryPlugin(parent) { }
virtual IAnObject *create(QObject *parent);
virtual ~MyObjectFactoryPlugin() { }
};
To cast the loaded plugin (a QObject) to AbstractFactoryPlugin safetly, you'll have to cast it to the intermediary class first.
AbstractFactoryPlugin * objectFactoryPlugin = qobject_cast< AbstractMyObjectFactoryPlugin * >(plugin);
The implicit assignment will cast it to the right base class.
Note: You'll have to check if the cast is successful first if you have other inheritance trees.