"undefined reference to" with singleton - c++

With the following code :
class DBConnection
{
// Methodes : private
private:
// Constructeur
DBConnection();
// Destructeur
~DBConnection();
// Methodes : public
public:
bool open();
bool close();
// Methodes : public : static
public:
static DBConnection * getSingleton();
// Variables
private:
static DBConnection * singleton;
QSqlDatabase conn;
QString driver,
host,
userName,
password,
DBName;
};
#endif // DBCONNECTION_HPP
#include "DBConnection.hpp"
// Initialisation du singleton dans l'espace global, car static
DBConnection * DBConnection::singleton = 0;
// Methodes : private
DBConnection::DBConnection() {
this->conn = QSqlDatabase::addDatabase("QMYSQL");
this->conn.setHostName("");
this->conn.setUserName("");
this->conn.setPassword("");
this->conn.setDatabaseName("");
}
DBConnection::~DBConnection(){};
// Methodes : public
bool DBConnection::open() {
bool rep = this->conn.isOpen()?true:this->conn.open();
if(!rep)
QMessageBox::critical(0, "Erreur critique !", "Impossible d'ouvrir la base de données !");
return rep;
}
DBConnection * DBConnection::getSingleton() {
if(singleton == 0)
singleton = new DBConnection;
return singleton;
}
#ifndef DAOMYSQLFACTORY_HPP
#define DAOMYSQLFACTORY_HPP
#include "InterfaceDAOFactory.hpp"
#include "DAO.hpp"
class DAOMySQLFactory : public InterfaceDAOFactory
{
// Methodes : private
private:
// Constructeur
DAOMySQLFactory();
// Destructeur
~DAOMySQLFactory();
// Methodes : public : heritées
public:
DAO * getDAOClient();
DAO * getDAOSite();
DAO * getDAOMachine();
// Methode : static
public:
static DAOMySQLFactory * getSingleton();
// Variables
private:
// Instance unique
static DAOMySQLFactory * singletonMySQLFactory;
};
#endif // DAOMYSQLFACTORY_HPP
#include "DAOMySQLFactory.hpp"
#include "DBConnection.hpp"
#include "DAOMySQLClient.hpp"
DAOMySQLFactory * DAOMySQLFactory::singletonMySQLFactory = 0;
// Methodes : private
// Constructeur
DAOMySQLFactory::DAOMySQLFactory() {}
// Destructeur
DAOMySQLFactory::~DAOMySQLFactory() {}
// Methode : static
DAOMySQLFactory * DAOMySQLFactory::getSingleton() {
if(singletonMySQLFactory == 0)
singletonMySQLFactory = new DAOMySQLFactory;
return singletonMySQLFactory;
}
// Methodes : public : heritee
DAO * DAOMySQLFactory::getDAOClient() {
return 0;
}
...
#include <QApplication>
#include "WinMain.h"
//TEST
#include "DAOPersistenceFactory.hpp"
#include "DAO.hpp"
#include "DAOMySQLFactory.hpp"
#include "DBConnection.hpp"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
//TEST
InterfaceDAOFactory * idao = DAOPersistenceFactory::getDAOFactory(DAOPersistenceFactory::MySQL);
DAO * d = idao->getDAOClient();
DBConnection::getSingleton();
WinMain fen;
fen.show();
return app.exec();
}
#ifndef DAO_HPP
#define DAO_HPP
#include <QString>
#include <QStringList>
#include <QSqlQuery>
class DAO {
// Methodes : public
public:
DAO();
virtual ~DAO();
// Methodes : public : abstraites
public:
virtual QStringList findAll() = 0;
// Variable
protected:
QSqlQuery allQuery;
};
#endif // DAO_HPP
#include "DAO.hpp"
DAO::DAO() {}
DAO::~DAO(){}
#ifndef DAOMYSQLCLIENT_HPP
#define DAOMYSQLCLIENT_HPP
#include <QString>
#include <QStringList>
#include <QSqlQuery>
#include "DAO.hpp"
#include "DBConnection.hpp"
class DAOMySQLClient : public DAO
{
// Methodes : public
public:
DAOMySQLClient();
// DAOMySQLClient(DBConnection * connection);
//Variables
private:
DBConnection * conn;
QSqlQuery byIdQuery,
byNameQuery;
};
#endif // DAOMYSQLCLIENT_HPP
#include <QMessageBox>
#include <QSqlError>
#include <QVariant>
#include "DAOMySQLClient.hpp"
// Methodes : public
// Constructeur
DAOMySQLClient::DAOMySQLClient() {}
// Constructeur
// DAOMySQLClient::DAOMySQLClient(DBConnection * connection) {
// this->conn = connection;
// this->conn->open();
// initQueries();
// }
...
Why i have a
undefined reference to 'DBConnection::getSingleton()'
collect2:ld returned 1 exit status
in main() and DAOPersistenceFactory::getDAOFactory(DAOPersistenceFactory::MySQL); not whereas it seems to have the same implementation ?

I have the feeling that you forgot to add DBConnection.cpp to your .pro file.
If you did, try re-running qmake. Also try to make clean.
I had lots of weird issues with out-of-date object files in the past. ;)

Related

Register custom type in Qt with QJsEngine

I have a custom class named LObject, with a method "test" i want to call.I have a method registered in a QJSEngine that returns an instance of LObject.
I get the error message when executing the method :
"Error: Unknown method return type: LObject"
I tried to register my type with Q_DECLARE_METATYPE, but then i can't call the method of my LObject.
What's the way to do it ?
Edit : A Minimal example with 3 files
server.h :
#ifndef SERVER_H
#define SERVER_H
#include <QObject>
#include <QString>
#include <QQmlEngine>
#include <QQuickView>
#include <QQmlContext>
#include <qqml.h>
class TObject : public QObject
{
Q_OBJECT
QML_ELEMENT
public :
TObject(QObject * parent = nullptr, const QString & data = "") : QObject(parent) ,m_data(data){}
TObject(const TObject & other) : QObject() ,m_data(other.m_data) {}
~TObject(){};
TObject& operator=(const TObject & other) { m_data = other.m_data;return *this;}
Q_INVOKABLE QString getData() { return m_data;}
Q_INVOKABLE void setData(const QString & data) {m_data = data;}
private :
QString m_data;
};
class Server : public QObject
{
Q_OBJECT
public :
QQmlEngine * newEngine()
{
QQmlEngine * ret = new QQmlEngine(this);
ret->rootContext()->setContextProperty("Server",this);
return ret;
}
Q_INVOKABLE TObject newTObject() { return TObject();}
};
Q_DECLARE_METATYPE(TObject)
#endif // SERVER_H
main.cpp :
#include "server.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Server s;
QQmlEngine * e = s.newEngine();
QQuickView view(e,nullptr);
view.setSource(QUrl("test.qml"));
view.show();
return a.exec();
}
test.qml
import QtQuick 2.9
import QtQuick.Window 2.9
Text
{
function test()
{
let t = Server.newTObject() //test.qml:8: Error: Unknown method return type: TObject
t.setData("TEST")
return t.getData()
}
text : test();
}
Solved !
qmlRegisterInterface<TObject>("TObject",1);
and then the methods have to return a TObject*.
Registering QMetaType::qRegisterMetaType should fix your issue. In short, QT meta-object needs this to match the return type's name to your class' name:
qRegisterMetaType<TObject>();

Qt C++ inner class access to outer class

I have a question again:
I have a class PBV t(inherits from Tab) hat has a class Geometry. Geometry is the parent of Geo_1. From Geo_1 I want to have access to methods of PBV ( e.g. printContent . How do I do that? I am able to create Signal-Slots but since I have to use methods of PBV often that would make lots of Signal-Slots.
Here is my code:
PBV.h:
#include "../Geometry/Geo_1.h"
class PBV : public Tab
{
Q_OBJECT
public:
explicit PBV (QWidget *parent = 0);
~ PBV ();
virtual void printContent( QStringList *const qsl);
private:
Geo_1 *GEO_1;
Geometry *GEO;
}
PBV.cpp:
…
Geo_1 *GEO_1;
GEO_1 = new Geo_1(this);
GEO_1->set_LNE_default();
…
.
Geo_1.h:
#ifndef GEO_1_H
#define GEO_1_H
#include "Geometry.h"
#include "../Tabs/PBV.h"
class Geo_1: public Geometry
{
Q_OBJECT
public:
Geo_1 (QObject *_parent = 0);
virtual void set_LNE_default();
};
#endif // GEO_1_H
.
Geo_1.cpp:
#include "Geometry.h"
#include <QDebug>
#include "Geo_1.h"
#include "../Tabs/PBV.h"
Geo_1::Geo_1(QObject*_parent)
: Geometry(_parent) {}
void Geo_1::set_LNE_default()
{
// here I want to use printContent
}
.
Geometry.h:
#ifndef GEOMETRY_H
#define GEOMETRY_H
#include <QObject>
class Geometry : public QObject
{
Q_OBJECT
public:
Geometry(QObject *_parent=0);
~Geometry();
virtual void set_LNE_default();
};
#endif // GEOMETRY_H
.
Geometry.cpp:
#include "Geometry.h"
#include <QDebug>
Geometry::Geometry(QObject *_parent)
: QObject(_parent) {}
Geometry::~Geometry(){}
void Geometry::set_LNE_default() { }
One approach, as referred to by comments, is to keep track of the parent class in the constructor of the child:
In Geometry.h, add a private member variable:
private:
PBV* m_pParentPBV;
Then, in the constructor in Geometry.cpp, set this to the parent you are already passing:
Geometry::Geometry(QObject *_parent)
: QObject(_parent)
{
m_pParentPBV = dynamic_cast<PBV*>(_parent);
}
Now you can call methods on the parent using m_pParentPBV->printContent() etc.

Error while declaring QVector of class type

Getting error while declaring QVector of class type in Qt.
Error :"incomplete type is not allowed"
I didn't understand what causes this error.
if i #include "storage.h" in main.cpp and declare a Qvector of class storeage it works fine but when i do the same in waveform class it reports an error.
I've tried forward declaring storage class in waveform class but still getting the same error.
Any Help??
main.cpp
#include "test_subject_02.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TEST_SUBJECT_02 w;
w.show();
return a.exec();
}
test_subject_02.h
#ifndef TEST_SUBJECT_02_H
#define TEST_SUBJECT_02_H
#include <QtGui/QMainWindow>
#include "ui_test_subject_02.h"
#include"waveform.h"
#include "storage.h"
class TEST_SUBJECT_02 : public QMainWindow
{
Q_OBJECT
public:
TEST_SUBJECT_02(QWidget *parent = 0, Qt::WFlags flags = 0);
waveform *wv;
~TEST_SUBJECT_02();
private:
Ui::TEST_SUBJECT_02Class ui;
};
#endif // TEST_SUBJECT_02_H
test_subject_02.cpp
#include "test_subject_02.h"
TEST_SUBJECT_02::TEST_SUBJECT_02(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
QVector<storage> ser; //works fine here
wv->readfile("e:/testing2/result/3/abc.cur");
}
TEST_SUBJECT_02::~TEST_SUBJECT_02()
{
}
waveform.h
#ifndef WAVEFORM_H
#define WAVEFORM_H
#include "storage.h"
#include <QObject>
class waveform : public QObject
{
Q_OBJECT
public:
waveform(QObject *parent=0);
void readfile(QString);
QVector <storage> myvector ; // incomplete type is not allowed
~waveform();
private:
};
#endif // WAVEFORM_H
waveform.cpp
#include "waveform.h"
waveform::waveform(QObject *parent)
: QObject(parent)
{
}
void waveform::readfile(QString file)
{
QVector<storage> sw; //again error incomplete type is not allowed
}
waveform::~waveform()
{
}
storage.h
#ifndef STORAGE_H
#define STORAGE_H
#include <QObject>
class storage : public QObject
{
Q_OBJECT
public:
storage(QObject *parent);
storage();
storage(QString,QString);
~storage();
private:
QString x;
QString y;
};
#endif // STORAGE_H
storage.cpp
#include "storage.h"
storage::storage(QObject *parent)
: QObject(parent)
{
}
storage::storage(QString xcord,QString ycord)
{
x=xcord;
y=ycord;
}
storage::storage()
{
}
storage::~storage()
{
}
You need to explicitly include QVector in necessary file (waveform.h i believe), since QT uses a lot of forward declarations, while they appear as correct classes in IDE, but they won't compile, if proper definition is not included in file.

QT c++ crashes while calling method of class from another class using signals and slots

I am trying to create QQuickWidget based application.
What i am trying to do:
Class A(game.h) and Class B(gamestate.h) are forward declared. Class A is main QQuickWidget class with methods. Class B QObject derived class contains signals, slots, variables and methods.
Class B Variable values can set from class A -- Working
When variable value changes signal should be emitted -- working
when signal was emitted slot method should be called in class B -- working
Class B should invoke a method in class A -- working
Class A should create another qquickwidget -- NOT WORKING
(No compiling error. Application crashes on load)
I tried to call from class A and showIntro() function working fine. But when tried to call from class B its not working.
Game.h
#ifndef GAME_H
#define GAME_H
#include <QQuickWidget>
class GameState;
class Game: public QQuickWidget
{
Q_OBJECT
public:
Game();
GameState *gameState;
void showIntro();
public slots:
void onStatusChanged(QQuickWidget::Status);
};
#endif // GAME_H
Game.cpp
#include "game.h"
#include <QQuickWidget>
#include <QDebug>
#include "gamestate.h"
Game::Game(): QQuickWidget()
{
gameState = new GameState(this);
mainScreen = new QQuickWidget();
connect(this, SIGNAL(statusChanged(QQuickWidget::Status)), this, SLOT(onStatusChanged(QQuickWidget::Status)));
setFixedSize(450, 710);
setSource(QUrl("qrc:/EmptyScreen.qml"));
}
void Game::onStatusChanged(QQuickWidget::Status status)
{
switch(status)
{
case QQuickWidget::Ready:
qDebug() << "hi";
gameState->setValue(1);
//showIntro();
break;
case QQuickWidget::Error:
qDebug() << "Error";
break;
}
}
void Game::showIntro()
{
mainScreen->setSource(QUrl("qrc:/MainScreen.qml"));
mainScreen->setAttribute(Qt::WA_TranslucentBackground);
mainScreen->setParent(this);
}
Here is my Gamestate.h
#ifndef GAMESTATE_H
#define GAMESTATE_H
#include <QObject>
class Game;
class GameState : public QObject
{
Q_OBJECT
public:
explicit GameState(QObject *parent = 0);
int value() const {return m_value; }
Game *game;
signals:
void valueChanged(int newValue);
public slots:
void setValue(int value);
void stateChanged(int value);
private:
int m_value;
};
#endif // GAMESTATE_H
GameState.cpp
#include "gamestate.h"
#include "game.h"
GameState::GameState(QObject *parent) : QObject(parent)
{
m_value = 0;
connect(this,SIGNAL(valueChanged(int)), this, SLOT(stateChanged(int)));
}
void GameState::setValue(int value)
{
if(value != m_value)
{
m_value = value;
emit valueChanged(value);
}
}
void GameState::stateChanged(int value)
{
if(value == 1)
{
game->showIntro();
}
}
and my final main.cpp
#include <QApplication>
#include <QQmlApplicationEngine>
#include "game.h"
Game *game;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
game = new Game();
game->show();
return app.exec();
}
Pls suggest me what could be the issue.
Member variable Game* game of class GameState is not initialized and therefore the program crashes when trying to dereference the pointer within GameState::stateChanged().
Change the constructor of GameState to the following:
// in gamestate.h
explicit GameState(Game *parent = 0);
// in gamestate.cpp
GameState::GameState(Game *parent) : QObject(parent), game(parent)
{
m_value = 0;
connect(this,SIGNAL(valueChanged(int)), this, SLOT(stateChanged(int)));
}

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.