Using QHash in a custom class - c++

I am newbie in Qt and learning to handle how QHash works. On working with this example I dont understand why this throws me an error. I may miss something, but please guide me to learn this.
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QHash<QString,Person> hash;
QString key="1";
Person p;
p.name = name;
p.number = an;
hash.insert(key,p);
return a.exec();
}
person.h
class Person
{
public:
Person();
Person(QString name,QString num);
bool operator==(const Person & other) const; //== overloading to assign in QHash
QString name,number;
};
person.cpp
Person::Person()
{
}
Person::Person(QString name, QString num)
{
this->name=name;
this->number=num;
}
bool Person::operator==(const Person & other) const
{
bool state;
if (name == other.name )
state = true;
else
state = false;
return state;
}
and the error is:-'qHash':none of the 17 overloads could convert all the argument type.I knw im missing something.Please guide me.

You need the global qHash() function.
A QHash's key type has additional requirements other than being an
assignable data type: it must provide operator==(), and there must
also be a qHash() function in the type's namespace that returns a hash
value for an argument of the key's type.
See this for more info about that.

The code you've provided is not complete and not compilable - e.g. The symbol name is not found, no includes.
The op == is not required when you use the class as value. The only one requirement for value-classes - a default constructor.
I think you problem was something else. If you provided the complete code and the complete list of errors I could tell you what exactly.
Below you'll find the working version of you code-snippet. (For simplicity, everything in one file)
main.cpp
#include <QApplication>
#include <QHash>
#include <QString>
class Person
{
public:
Person(QString name=QString::null,QString num=QString::null);
QString name,number;
};
Person::Person(QString _name, QString _num)
:name(_name),number(_num)
{
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QHash<QString,Person> hash;
QString key="1";
Person p("Orhan Kemal", "1914");
hash.insert(key,p);
return a.exec();
}
Regards,
Valentin
EDIT:
Initialized members not in body

Related

Qt WebAssembly and inheritance of QVector

I'm trying to us Qt for WebAssembly. I'm using QVector, but I want to add some convenient finder methods. So I've tried subclassing like the code below. The compiler complains that vec.begin() and vec.end() do not exist. If I change vec from a Foo_Vector to a QVector (no subclassing), it works.
Other methods from QVector also become undefined when using the subclass version -- such as size.
I tried defining a method on Foo_Vector:
size_t size() const { return QVector<Foo>::size(); }
That produces an error about non-static methods. So I tried to do this:
QVector<Foo> * ptr = static_cast<QVector<Foo>>(this);
And that produces an error that there's no conversion from a Foo_Vector * to a QVector *.
Does anyone have an explanation? Do I have to do this through composition instead and implement passthrough methods for anything I want to do?
#include <QCoreApplication>
#include <QVector>
class Foo {
public:
int a;
int b;
};
class Foo_Vector: public QVector<Foo> {
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Foo_Vector vec;
for (auto it = vec.begin(); it != vec.end(); ++it) {
}
return a.exec();
}

QDataStream is becoming Readonly

I have two classes named IPCBase and DispatchData. Now I want to pass QDataStrean Object drom IPCBase to DispatchData. First I tried to send it directly using Connect Statement. But it is giving error like QDataStream object is not registered in QRegisterMatatype.
edit :: I have refered this link as well
When, where and why use namespace when registering custom types for Qt
So I have done something like
typedef QDataStream* myDataStrem;
Q_DECLARE_METATYPE(myDataStrem)
and then connect statement in another class(DispatchData)
connect(mpThrIPCReceiver, SIGNAL(dispatchReadData(const int&, myDataStrem)),
this, SLOT(onIPCDataReceived(const int&, myDataStrem)));
onIPCDataReceived Slot
void DispatchData::onIPCDataReceived(const int& msgType, myDataStrem dataReceived)
{
// dataReceived >> str1; Here it is giving error
// qDebug()<<"is"<<str1;
MemberFuncPointer f = mIPCCommandMapper.value(msgType);
(this->*f)(*dataReceived);
//This is function pointer which will rout it to respective function depending on the Message type.
and then it will come here
void DispatchData::onStartCountingCycle(QDataStream &dataReceived)
{
int data = 0;
dataReceived >> data; //Here it is crashing
//Giving error like
//pure virtual method called
//terminate called without an active exception
// I have debugged it and here dataReceived is becoming Readonly.
}
It seems like you're passing around a dangling pointer: the data stream seems to not exist anymore by the time the receiving thread gets to it. Even if you extended its lifetime in the source object, it's a bad idea to pass a raw pointer through signal-slot connections. If the source class might vanish while the receiver thread has a pending slot call, you'll still be using a dangling pointer at the receiver. You'd be best served by passing around a QSharedPointer or std::shared_ptr.
The following works, you can of course use any type in the shared pointer.
#include <QtCore>
#include <cstdio>
struct Class : public QObject {
Q_SIGNAL void source(QSharedPointer<QTextStream>);
Q_SLOT void destination(QSharedPointer<QTextStream> stream) {
*stream << "Hello" << endl;
}
Q_OBJECT
};
Q_DECLARE_METATYPE(QSharedPointer<QTextStream>)
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
Class c;
c.connect(&c, &Class::source, &c, &Class::destination, Qt::QueuedConnection);
auto out = QSharedPointer<QTextStream>(new QTextStream(stdout));
emit c.source(out);
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
*out << "About to exec" << endl;
return app.exec();
}
#include "main.moc"
Output:
About to exec
Hello
On modern Qt (5.6 at least), you don't need to call qRegisterMetatype in this case.
The same using std::shared_ptr:
// https://github.com/KubaO/stackoverflown/tree/master/questions/datastream-pass-37850584
#include <QtCore>
#include <cstdio>
#include <memory>
struct Class : public QObject {
Q_SIGNAL void source(std::shared_ptr<QTextStream>);
Q_SLOT void destination(std::shared_ptr<QTextStream> stream) {
*stream << "Hello" << endl;
}
Q_OBJECT
};
Q_DECLARE_METATYPE(std::shared_ptr<QTextStream>)
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
Class c;
c.connect(&c, &Class::source, &c, &Class::destination, Qt::QueuedConnection);
auto out = std::make_shared<QTextStream>(stdout);
emit c.source(out);
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
*out << "About to exec" << endl;
return app.exec();
}
#include "main.moc"

object inicialization with constructor in QT, no matching function to call

I'm using Mysql 5.6 with Qt5 and creating a class to encapsulate a database connection.
When I try to create an object in the main with dbConnect conn = new dbConnect("localhost", "test1","test","user"); I get and error telling me I need a conversion from dbConnect* to a non-scalar type.
Reading other posts I've seen this could be due to the type of inicialization I'm trying because it's not a good practice in C++ and should be something like dbConnect conn("localhost", "test1","test","user"); but, changing it like that, instead of getting the conversion error I get now a no matching function for call to QSqlDatabase::setHosTname(std::string&) and same with the other methods needed for connecting such as setDatabaseName, setUserName and setPassword
Could it be because of the std::string I'm using?
Or how should I create the object?
This is m y header db.h:
#ifndef DB
#define DB
#include <QSqlDatabase>
#include <string>
class dbConnect:QSqlDatabase
{
public:
dbConnect(std::string host, std::string name,std::string user, std::string pass);
bool createConnection(std::string host, std::string name,std::string user, std::string pass);
private:
QSqlDatabase dbObject;
};
#endif // DB_
Next here it is its implementation db.cpp:
#include<QSqlDatabase>
#include <QMessageBox>
#include <QSqlError>
class dbConnect:QSqlDatabase
{
private:
QSqlDatabase dbObject;
public:
dbConnect(std::string host, std::string name,std::string user, std::string pass)
{
if(createConnection(host, name, user, pass))
{
QMessageBox::information(0,"Connection Status","Connection established with database");
}
else
{
QMessageBox::critical(0,QObject::tr("Error connecting to database"),dbObject.lastError().text());
}
}
bool createConnection(std::string host, std::string name,std::string user, std::string pass)
{
dbObject = QSqlDatabase::addDatabase("QMYSQL");
dbObject.setHostName(host);
dbObject.setDatabaseName(name);
dbObject.setUserName(user);
dbObject.setPassword(pass);
if(!dbObject.open())
{
return false;
}
else
{
return true;
}
}
};
UPDATE
Took #gengisdave and #R Sahu solutions and now I'm trying to create an object in the main. If I try dbConnect conn(); it works fine even if the constructor takes for paremeter but, if I trye dbConnect conn("localhost","test1","test","user"); compiler gives me an error of undefined reference to dbConnect::dbConnect(std::string,std::string,std::string,std::string).
When you use:
dbConnect conn = new dbConnect("localhost", "test1","test","user");
the RHS is of type dbConnect* while the LHS is of type dbConnect. That is not correct. The compiler cannot take a pointer and assign it to an object.
You can use:
dbConnect* connPtr = new dbConnect("localhost", "test1","test","user");
or
dbConnect conn("localhost", "test1","test","user");
Other problems
bool createConnection(std::string host, std::string name,std::string user, std::string pass)
{
dbObject = QSqlDatabase::addDatabase("QMYSQL");
dbObject.setHostName(host);
dbObject.setDatabaseName(name);
dbObject.setUserName(user);
dbObject.setPassword(pass);
if(!dbObject.open())
{
return false;
}
else
{
return true;
}
}
is not right. You probably need:
bool createConnection(std::string host, std::string name,std::string user, std::string pass)
{
// Since this class is derived from QSqlDatabase,
// you can use:
this->addDatabase("QMYSQL");
this->setHostName(QString::fromStdString(host));
this->setDatabaseName(QString::fromStdString(name));
this->setUserName(QString::fromStdString(user));
this->setPassword(QString::fromStdString(pass));
if(!this->open())
{
return false;
}
else
{
return true;
}
}
Also, remove the member variable
QSqlDatabase dbObject;
You don't need it since the class is already derived from QSqlDatabase. You'll need to use that only if you don't derive from QSqlDatabase
QSQlDatabase::setHostName requires a parameter of type QString, while you provide a std::string; the same with the next 3 lines
you can change that lines to
this->setHostName(QString::fromStdString(host));
this->setDatabaseName(QString::fromStdString(name));
this->setUserName(QString::fromStdString(user));
this->setPassword(QString::fromStdString(pass));
EDIT: it works fine
main.cpp
#include <QApplication>
#include "db.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
dbConnect connection("localhost", "test1", "test", "user");
dbConnect *conn = new dbConnect("localhost", "test1", "test", "user");
}
db.cpp
#include <QSqlDatabase>
#include <QMessageBox>
#include <QSqlError>
#include "db.h"
dbConnect::dbConnect(std::string host, std::string name,std::string user, std::string pass)
{
if ( createConnection(host, name, user, pass) )
QMessageBox::information(0, "Connection Status", "Connection established with database");
else
QMessageBox::critical(0,QObject::tr("Error connecting to database"),dbObject.lastError().text());
}
bool dbConnect::createConnection(std::string host, std::string name,std::string user, std::string pass)
{
this->dbObject = QSqlDatabase::addDatabase("QMYSQL");
this->dbObject.setHostName(QString("localhost"));
this->dbObject.setDatabaseName(QString("test.txt"));
this->dbObject.setUserName(QString("test"));
this->dbObject.setPassword(QString("test"));
return this->dbObject.open();
}
db.h
#ifndef DB_H
#define DB_H
#include <QSqlDatabase>
#include <string>
class dbConnect:QSqlDatabase
{
public:
dbConnect(std::string host, std::string name,std::string user, std::string pass);
bool createConnection(std::string host, std::string name,std::string user, std::string pass);
private:
QSqlDatabase dbObject;
};
#endif
compiled with: gcc db.cpp main.cpp -I/usr/include/qt5/QtSql -I/usr/include/qt5/QtWidgets -I/usr/include/qt5 -fPIC -o main -lstdc++ -lQt5Sql -lQt5Core -lQt5Widgets

c++ 2 Constructor 1 Object, How to?

I have to set up an object and, after an user chose, i have to change some param into the object but not every each.
example:
{
class Champ
{
private:
int hp;
std::string class;
public:
Champ();
Champ(std::string chose);
};
Champ::Champ() {hp=10; class="";}
Champ::Champ(std::string chose) {class = chose;}
main()
{
Champ Test;
std::string chose;
getline(cin,chose);
Test(chose);
return 0;
}
this code give me an error.
i need hp equal for all "Champ" created but class can be changed.
The hp can't be "const" because this value may undergo changes...
how can i do this? :/
The comments in the code below should explain what is going on well enough...
#include <iostream>
#include <string>
class Champ {
int hp;
std::string job;
public:
Champ():
hp(10) { } // don't need to explicitly initialize `job` because the default constructor for string does what we want.
explicit Champ(const std::string& choose):
hp(10),
job(choose) { }
};
int main(int argc, const char * argv[]) {
using namespace std;
// this is most like how you had it with the compile error fixed.
{
Champ test; // this creates a Champ object using the default constructor
string choose;
getline(cin, choose);
test = Champ(choose); // this creates a new Champ object and assigns it to test... Throwing away the one that was created earlier.
}
// this is, imho, a better way to do it:
{
string choose;
getline(cin, choose);
auto test = Champ(choose); // declare the variable as late as possible, and after you have all the data for its construction. That way, you only make one of them.
}
return 0;
}

user's arguments are empty with QCoreApplication in mysterious cases

I'm trying to create a console application with Qt and been facing really strange behavior when attempting to retrieve the arguments. My class is derived from QCoreApplication which has a function that should normally put all the args in some list of strings. But in some cases that call ends in a segmentation fault.
Here's the code:
main.cpp
#include "Diagramm.h"
int main(int argc, char *argv[])
{
Diagramm application(argc, argv);
application.run();
return EXIT_SUCCESS;
}
Diagramm.h
#include <QCoreApplication>
#include <iostream>
#include <QStringList>
#include <QFile>
#include <QDebug>
class Diagramm : public QCoreApplication
{
Q_OBJECT
public:
Diagramm(int argc, char *argv[]);
void run();
private:
void testArguments();
signals:
public slots:
};
Diagramm.cpp
#include "Diagramm.h"
Diagramm::Diagramm(int argc, char *argv[]) : QCoreApplication(argc, argv)
{
//std::cout << "calling Diagramm constructor" << std::endl;
}
void Diagramm::run()
{
testArguments();
}
void Diagramm::testArguments()
{
//get source and target files from arguments
QStringList arguments = this->arguments();
if(arguments.count() < 2)
{
std::cout << "Missing arguments" << std::endl;
return exit(1);
}
}
When compiling and executing the code above, everything works fine, BUT when I uncomment the line in Diagramm's constructor I've got a segmentation fault on the first line of function testArguments (the call to arguments())
I've been on that for hours, reading Qt's doc, forums... Does anyone know where that can come from? Any idea would be greatly appreciated.
Note : I'm not calling the exec function on purpose because I don't need any event loop.
Q(Core)Application wants argc and argv by reference, so your constructor should read
Diagramm(int& argc, char **argv[])
If you don't to this, it may work in some cases and lead to segfaults or strange behavior in others, as you encountered. Seems to be a common error and isn't easy to spot when reading the documentation.
arguments() is a static function so the line should be:
QStringList arguments = QCoreApplication::arguments();