Linker error: undefined reference to class method - qt

I have following very simple Qt project:
I have
#ifndef ABSTRACTWIDGET_H
#define ABSTRACTWIDGET_H
#include <QWidget>
#include <QVariant>
namespace Ui {
class AbstractWidget;
}
class AbstractWidget : public QWidget
{
Q_OBJECT
public:
explicit AbstractWidget(const QString &name, QWidget *parent = 0);
~AbstractWidget();
QString getName();
virtual void setValue(const QVariant & value);
protected:
Ui::AbstractWidget *ui;
};
#endif // ABSTRACTWIDGET_H
and
#ifndef SLIDERWIDGET_H
#define SLIDERWIDGET_H
#include "abstractwidget.h"
#include <QSlider>
class SliderWidget : public AbstractWidget
{
Q_OBJECT
public:
explicit SliderWidget(const QString & name, int min, int max, QWidget *parent = 0);
~SliderWidget();
void setValue(const QVariant & value);
private:
QSlider * slider;
};
#endif // SLIDERWIDGET_H
I just made setValue virtual at the super class Abstractwidget, which drops follwing linker error:
moc_abstractwidget.cpp:-1: Fehler: undefined reference to
`AbstractWidget::setValue(QVariant const&)'
collect2.exe:-1: Fehler: error: ld returned 1 exit status
Rebuilding All and Cleaning up did not help. Why is it failing to link?
Abstract is a bad nomencalture, sorry my bad. Consider it as a super class (not abstract) from which I derive other classes.
I inject in a MainWindow::Ui::QVBoxLayout dynamically those AbstractWidget classes (for instance I have multiple SliderWidgets and ColorPickerWidget : public Abstractwidget as well). I just wanted to keep it simple.
Why derive? I have multiple QWidgets (besides SliderWidget) deriving from AbstractWidget class. All of them have a QString name. I wanted to provide that name in the base class ==> AbstractWidget.
Why virtual void setValue(): Every derived class has somesting like a slider, colorpicker etc. I implement in each derived class a setValue(QVariant) so that the colorpicker sets the QColor(QVariant::toString()) and the SliderWidget sets the sliderValue with setValue(QVariant::toInt()), etc..
setValue is public everywhere (virtual base class and derived implementations).

Related

QML, How to correctly expose c++ type - got "undefined symbol"

I have a class that returns a list of custom objescts, to view in qml
#include <QObject>
#include "networkinterface.h"
class Network : public QObject {
Q_OBJECT
public:
explicit Network(QObject *parent = 0);
Q_INVOKABLE QList<NetworkInterface> getNetworkAdaptors();
private:
QList<NetworkInterface> networkAdaptors; };
At main.qml i call this method as
model: network.getNetworkAdaptors()
It all was working when NetworkInterface was a struct, but when i converted it to a class, can't make it work.
Class NetworkInterface is inherited from QObject and got properties
class NetworkInterface : public QObject
{
Q_OBJECT
public:
NetworkInterface();
QString name;
QString description;
const QString &getName() const;
void setName(const QString &newName);
const QString &getDescription() const;
void setDescription(const QString &newDescription);
...
private:
Q_PROPERTY(QString name READ getName CONSTANT)
Q_PROPERTY(QString description READ getDescription CONSTANT)
};
So the error i got is :
main.cpp.o:-1: error: Undefined symbols for architecture x86_64:
"NetworkInterface::NetworkInterface()", referenced from:
QtPrivate::QMetaTypeForType<NetworkInterface>::getDefaultCtr()::'lambda'(QtPrivate::QMetaTypeInterface const*, void*)::operator()(QtPrivate::QMetaTypeInterface const*, void*) const in mocs_compilation.cpp.o
Network::getNetworkAdaptors() in network.cpp.o
_main in main.cpp.o
I suspect it is wrong type expose, as with sctruct it was working fine, how to do that correctly?
UPD: in NetworkInterface i have following constructors:
NetworkInterface();
NetworkInterface(const NetworkInterface &obj);
NetworkInterface & operator=( const NetworkInterface & obj);
Without them i can't push_back(networkInterface) to the list of interfaces, as it requires copy constructor. Also list of pointers won't work for qml as a model, it must be exactly objects list.
When i copy all code in NetworkInterface and leave only above constructors, it is minimal code that gives a error.
Default constructor was missing, adding
NetworkInterface::NetworkInterface(QObject *parent) : QObject(parent)
{
}
Resoled a problem

Connection of pure virtual signal of interface class

I want to connect some object's signals derived from an interface class.
The connection is done in QWidget::listenToAnimal(AnimalInterface*).
This does not work because qt_metacall is not a member of 'AnimalInterface' and static assertion failed: No Q_OBJECT in the class with the signal.
Of course AnimalInterface does not have the Q_OBJECT macro and does not inherit QObject because it is an interface...
I want to connect through the interface class because I do not want to manually retype the same code for Cat and for Dog.
Is it possible to connect the signal the way I want to? Perhaps with templates? Is this perhaps a lambda-specific problem?
header:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class AnimalInterface{
public:
virtual ~AnimalInterface();
virtual void makeSound() = 0;
/*signals*/
virtual void madeSound() = 0;
};
Q_DECLARE_INTERFACE(AnimalInterface,"interface")
class Dog : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};
class Cat : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};
class Widget : public QWidget
{
Q_OBJECT
Cat *cat_;
Dog *dog_;
public:
Widget(QWidget *parent = 0);
~Widget();
void listenToAnimal(AnimalInterface *animal);
};
#endif // WIDGET_H
cpp:
#include "widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
dog_ = new Dog;
cat_ = new Cat;
listenToAnimal(dog_);
listenToAnimal(cat_);
dog_->makeSound();
cat_->makeSound();
}
void Widget::listenToAnimal(AnimalInterface *animal)
{
connect(animal, &AnimalInterface::madeSound,
this,
[](){
qDebug()<<"animal made sound";
});
}
Widget::~Widget()
{
}
void Cat::makeSound()
{
qDebug()<<"Cat says miaow";
emit madeSound();
}
void Dog::makeSound()
{
qDebug()<<"Dog says wuff";
emit madeSound();
}
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
Since you know the derived type at compile type, you can connect to the proper, statically-known QObject-derived type. No need for dynamic casting or anything of the sort. You just don't want the listenToAnimal method to be available for non-AnimalInterface-inheriting types, though, even if it they have a compatible madeSound method:
C++11
#include <type_traits>
template< class T,
typename =
typename std::enable_if<std::is_base_of<AnimalInterface, T>::value>::type >
void listenToAnimal(T * animal) {
connect(animal, &T::madeSound, this, []{ qDebug() << "animal made sound"; });
}
C++03
template <class T>
void listenToAnimal(T * animal) {
Q_UNUSED(static_cast<AnimalInterface*>(animal));
connect(animal, &T::madeSound, this, &Widget::onAnimalMadeSound);
}
You can then use it without having to spell out the type - it's already known to the compiler:
listenToAnimal(dog_);
listenToAnimal(cat_);
If the derived type is not known at compile time, you have to dynamically cast to QObject and connect by name, not by method pointer. It will assert at runtime if you've passed in a wrong type - after all, it's not enough for it to be an instance of AnimalInterface, it also needs to be a QObject instance.
void listenToAnimal(AnimalInterface * animal) {
auto object = dynamic_cast<QObject*>(animal);
Q_ASSERT(object);
connect(object, SIGNAL(madeSound()), this, SLOT(onAnimalMadeSound()));
}
The fact that the type AnimalInterface has a virtual madeSound method is somewhat relevant - it guarantees that the derived class implements the method with such a signature. It doesn't guarantee that the method is a signal, though. So you should probably rethink your design and ask yourself: "What do I gain by using a static type system when I can't really use it for static type checking"?
Most likely you should make any methods that would nominally accept the AnimalInterface*, be parametrized and take a pointer to the concrete class. Modern code generators and linkers will deduplicate such code if type erasure leads to identical machine code.
Found a solution with templates. Did not work the first time I tried, obviously did something wrong first. Here it goes...
Just replace the corresponding parts from the example in the question (and remove definition of listenToAnimal from the source file):
header:
template<class T>
void listenToAnimal(AnimalInterface *animal)
{
T *animal_derivate = dynamic_cast<T*>(animal);
if (animal_derivate){
connect(animal_derivate, &T::madeSound,
this,
[](){
qDebug()<<"animal made sound";
});
}
}
cpp:
listenToAnimal<Dog>(dog_);
listenToAnimal<Cat>(cat_);
Update:
After trying Kuba Ober's answer, it seems like this is working best now:
template<typename T>
typename std::enable_if<std::is_base_of<AnimalInterface, T>::value,void>::type
listenToAnimal(T *animal)
{
connect(animal, &T::madeSound, this, [](){ qDebug()<<"animal made sound"; });
}
However, the one point still not working is how to connect if I create an animal like AnimalInterface *bird = new Bird, because it throws the same error that the base class does not have the signal.

How to store global data in QList

Can you explain a methods for storing program data with global access ?
I found these keywords:
- using static class to store data
- pass QList by value
- pass Qlist by reference
- use 'friend' keyword
but I cannot find any real example of storing global QList, as they say, it is a bad design to use global variables. Also there is a mention that using pointers on a QList is a bad idea because of implicit sharing (?).
So where should I store my Qlist for accessing it from a different class in an other .cpp ? So I have:
mainwindow.h
QList <SceneCard> sceneList;
QString mTitle;
public slots:
QString setValue()
{
return mTitle;
}
mainwindow.cpp
MainWindow::AddScene()
{
sceneCard = new SceneCard(sNumber);
sceneList.append(sceneCard);
mTitle = "Nejat is right!"
}
void MainWindow::showSceneCard()
{
SceneDialog D;
connect(D,SIGNAL(getValue()),this,SLOT(setValue()));
D.exec();
}
scenedialog.h
#ifndef SCENEDIALOG_H
#define SCENEDIALOG_H
#include <QDialog>
#include <QList>
namespace Ui {
class SceneDialog;
}
class SceneDialog : public QDialog
{
Q_OBJECT
public:
SceneDialog(QWidget *parent = 0);
~SceneDialog();
signals:
QString getValue();
private:
Ui::SceneDialog *ui;
QString myText;
};
scenedialog.cpp
#include "scenedialog.h"
#include "ui_scenedialog.h"
#include <QDebug>
SceneDialog::SceneDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::SceneDialog)
{
ui->setupUi(this);
myText = getValue();
qDebug() << myText; // myText is empty!!
}
You can put your list as a class member and use Qt's Signal/slot mechanism to access the list from other classes. Just make a signal in the target class, connect it to a slot in the class containing the list and make a connection between two objects of the classes. This way you can access any data member of other classes by connecting a signal to a slot returning that value and just emitting the signal and getting the return value.
For example if you have two classes like :
class A: public QObject
{
Q_OBJECT
public:
A(QObject *parent = 0);
~A();
signals:
int getValue();
private:
void someFunction()
{
int val = getValue();
}
};
class B
{
Q_OBJECT
public:
B(QObject *parent = 0);
~B();
public slots:
int getValue()
{
return someValue;
}
};
And connect the signal from an object of A to the slot in an object of B :
connect(a, SIGNAL(getValue()), b, SLOT(getValue()));
In class A you can access the value returned from getValue slot in B by just calling the signal and using the returned value.
Note that the two objects should be in the same thread for this to work. If they are in different threads then the connection type should be of type Qt::BlockingQueuedConnection :
connect(a, SIGNAL(getValue()), b, SLOT(getValue()), Qt::BlockingQueuedConnection);
Another way is two use static class members but it is not recommended unless you have a good reason to do it. If you have two classes like :
class A {
public:
static QList<int> list;
};
class B {
public:
void do_something();
};
You can access A's static data member from B like this:
void B::do_something()
{
int val = A::list[0];
...
};

Why can't I set a QObject parent in a class of which QObject is only an indirect base?

I have a class BatchItem that inherits QObject, plus several classes that inherit from BatchItem:
#ifndef BATCHITEM_H
#define BATCHITEM_H
#include <QObject>
class BatchItem : public QObject
{
Q_OBJECT
public:
virtual void start() = 0;
virtual void stop() = 0;
signals:
/* ... some signals ... */
};
#endif // BATCHITEM_H
Example of a class that inherits from BatchItem:
#ifndef VIDEOBATCHITEM_H
#define VIDEOBATCHITEM_H
#include "batchprocessing/batchitem.h"
#include <QtCore/QObject>
class VideoBatchItem : public BatchItem
{
Q_OBJECT
public:
explicit VideoBatchItem(/* ... */, QObject *parent = 0);
void start();
void stop();
private:
/* ... some private member variables ... */
};
#endif // VIDEOBATCHITEM_H
And this is the corresponding .cpp:
#include "videobatchitem.h"
VideoBatchItem::VideoBatchItem(/* ... */,
QObject *parent) :
/* ... */,
QObject(parent)
{
/* ... */
}
/* ... */
But when I try to compile, I get the following error:
error: type ‘QObject’ is not a direct base of ‘VideoBatchItem’
Of course I see that this is correct, as QObject is only an indirect base of VideoBatchItem. But why is that a problem?
Isn't that also the case for e.g. QAbstractScrollArea, which inherits from QFrame, which in turn inherits from QWidget? They all take a QWidget as their parent, although QAbstractScrollArea only indirectly inherits from QWidget.
Unfortunately I couldn't find an answer to that in neither the documentation nor the .cpp files of the named widget classes.
Since I cannot pass a QObject parent, is there still a way to use Qt's parent-child system for the destruction of my derived batch items?
You can't call QObject base constructor. It doesn't matter about type of parent parameter but call of QObject(QObject * parent). You should call in this case BatchItem() without parameter and call setParent(parent) in constructor body, or overload BatchItem(QObject *) constructor.

Qt subclassing from QWidget

I write my own class which subclass from QWidget
And this is my header file
#ifndef GRAPHMATRIX_H
#define GRAPHMATRIX_H
#include "treemodel.h"
#include <QWidget>
#include <Qt/qtableview.h>
class GraphMatrix : public QWidget
{
Q_OBJECT
public:
TreeModel& getModel();
GraphMatrix(QWidget* parent = 0);
void addTop(QString name);
void cutComponent(GraphMatrix* component, QVector<int> columns);
private:
TreeModel model;
QTableView* view;
public slots:
void changeValue(const QModelIndex& index);
};
#endif // GRAPHMATRIX_H
And I am getting this error
error C2248: 'QWidget::QWidget' : cannot access private member declared in class 'QWidget'
Can anyone help me?
Updated to add: I find answer, problem is in QList I must write QList. because QList is using copy constructor. Thank you for giving time for my problem
It looks like you are trying to call the default constructor of QWidget which is private. Instead, your constructor needs to call the public constructor of QWidget as follows:
GraphMatrix::GraphMatrix(QWidget* parent) : QWidget(parent) {}
I find answer, problem is in QList I must write QList. because QList is using copy constructor. Thank you for giving time for my problem

Resources