2

I am working at a university project with Qt version 4.7.2(I am using an old version because our teacher will use this version to review the project) on a Windows x86 machine but I have some problems while linking some function from the class Container to the class QListModelAdapter.

I've already tried running qmake again, clean and rebuild the project and deleting the build folder for building it from scratch but nothing of this worked, also checked my .pro file but seems like nothing wrong there.

qlistmodeladapter.h

#ifndef QLISTMODELADAPTER_H
#define QLISTMODELADAPTER_H

#include <QAbstractListModel>
#include "container.h"

class AddLayout;

class QListModelAdapter : public QAbstractListModel {
private:
    Container<articolo>* model;
    const AddLayout* insert;
public:
    QListModelAdapter(QObject* = nullptr, const AddLayout* = nullptr);
    ~QListModelAdapter() override;
    bool insertRows(int, int = 1, const QModelIndex& = QModelIndex()) override;
    bool removeRows(int, int = 1, const QModelIndex& = QModelIndex()) override;
};
#endif

qlistmodeladapter.cpp

#include "qlistmodeladapter.h"
#include "container.h"
#include "addlayout.h"
#include <QFont>

QListModelAdapter::QListModelAdapter(QObject* parent, const AddLayout* ins) :
    QAbstractListModel(parent),
    model(new Container<articolo>()), insert(ins) {}

bool QListModelAdapter::removeRows(int begin, int count, const QModelIndex& parent) {
    beginRemoveRows(parent, begin, begin + count - 1);
    model->removeEl(begin);
    endRemoveRows();
    return true;
}

bool QListModelAdapter::insertRows(int begin, int count, const QModelIndex& parent) {
    beginInsertRows(parent, begin, begin + count - 1);
    articolo art = articolo(new Computer(insert->getNome()));
    model->insertEl(art);
    endInsertRows();
    return true;
}

container.cpp

#include "container.h"
template<class T>
void Container<T>::insertEl(T& p)
{
    if (maxSize == size)
    {
        increaseSize();
    }
    iteratore it = end();
    *(it) = p;
    size++;
}
template<class T>
void Container<T>::removeEl(int j)
{
    if (j <= size)
    {
        iteratore it = begin();
        for(int i = 0; i <= (j-1); i++)
        {
            it++;
        }
        delete it.punt;
        iteratore aux = it;
        it++;
        for(int i = j; i < size-2; i++)
        {
            aux = it;
            aux++;
            it++;
        }
        size--;
    }
}

container.h

#ifndef CONTAINER_H
#define CONTAINER_H
#include "items.h"

template<class T>
class Container
{
    friend class iteratore;
private:
    T* vector;
    int size;
    int maxSize;
public:
    class iteratore {
// is defined correctly
    };
    Container(T* p = nullptr, int s = 0);//it is defined but not included
    void removeEl(int);
    void insertEl(T&);
};
#endif // CONTAINER_H

The incriminated function is removeEl and is where is get this error:

qlistmodeladapter.obj:-1: error: LNK2019: riferimento al simbolo esterno "public: void __cdecl Container<class articolo>::removeEl(int)" (?removeEl@?$Container@Varticolo@@@@QEAAXH@Z) non risolto nella funzione "public: virtual bool __cdecl QListModelAdapter::removeRows(int,int,class QModelIndex const &)" (?removeRows@QListModelAdapter@@UEAA_NHHAEBVQModelIndex@@@Z)

sorry but the language is set on Italian, the strange thing is that it works properly with insertEl so i don't know what to think.

I've already checked the .pro file so I'm not including it right now because there is a lot of code already.

Every help will be really appreciated, thank you a lot.

1 Answers1

0

Templates are not classes. Only when a template parameter is given to them, they will be seen as implementation. That being said, in your cpp file, the methods are just method templates, they are no method implementations (yet).

Now, when you try to call the method from a different translation unit (cpp file), the linker will try to find the symbol of the method implementation but cannot find it because the compiler will not have created the corresponding symbol in the cpp file because it was never called there with the corresponding template parameter.

The solution is quite easy: whoever uses your template, needs to have the method template available, too, so that a call to a method template will urge the compiler to create this needed implementation -> move the method implementations to your header file. You can delete your cpp file for this class template altogether.

Edit: by the way, you create memory leaks here because you call new on your container class but never delete. You have two clean possibilities here: Since you use Qt, you can use the memory management of it by letting Container inherit QObject. Then, in the constructor initialize QObject with the parent that you pass to it by your list view.

An alternative way is to use unique_ptr around your container instance in QListModelAdapter. New will still work and you can access the object via pointer. But it will be cleaned up automatically.

Of course, you could also just put the Container on the stack without pointer (just removing * and accessing the object with .).

Note that manually calling delete in your own destructor is not modern C++. It makes things more complicated and you would also need to implement copy constructor and copy assignment operator. This is not necessary or recommendable in year 2019 anymore. C++ is a fresh language that has multiple ways of preventing memory leaks when used idiomatically now.

And what I also see here (this starts to become a code review) is your naming. Q as prefix for macros, function names, class names and so on should just be used by Qt. If someone uses your code, they will be confused by your naming otherwise. For such user, it could well be that your class name is an actual Qt class that they have not heart of before.

IceFire
  • 4,016
  • 2
  • 31
  • 51
  • thanks! that was a stupid mistake from me, and thank you very much for all your other suggestions, I will modify the project as soon as possible. – Alessandro Rizzo Jun 07 '19 at 16:05