Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QSharedDataPointer with forward-declared class

The Qt documentation suggests that using the QSharedDataPointer with a visible implementation of its inferior is not typical.

So according to the small example snipped in the docs, I came up with the following source (SSCCE).

The interface: Model.h

The interface is straight forward, just the forward declaration of the private class and the handle class, with copy-ctor and d-tor declared:

#include <QtCore/QSharedDataPointer>

class ModelPrivate;
class Model {
    public:
        Model();
        Model(const Model &other);
        ~Model();

        QSharedDataPointer<ModelPrivate> d;
};

Private header: Model_p.h

Just declares and defines the inferior class.

#include <QSharedData>
class ModelPrivate:
    public QSharedData {

    public:

};

Implementation: Model.cc

Consisting of the implementation of the c-tors/d-tor, taken from the docs.

#include "Model.h"
#include "Model_p.h"

class ModelPrivate:
    public QSharedData {

};

Model::Model():
    d(new ModelPrivate()) {

}

Model::Model(const Model &other):
    d(other.d) {

}

Model::~Model() {

}

Use case: main.cc

Where it all failed.

#include <QString>
#include "Model.h"

int main(int argc, char *argv[]) {
    QString s1, s2;
    s2 = s1;

    Model m1, m2;
    m2 = m1;
}

Just two instances and an assignment, as one would do with any other shared class as well. However, it fails badly because of

invalid use of incomplete type 'class ModelPrivate'

I can't figure out how to make this work the expected way according to the documentation, i.e. without fully declaring the private class in the header as well. I know it works when doing so but I'd like to understand the docs. The example of assigning shared classes is included in the docs as well. From the above-linked docs:

The copy constructor is not strictly required here, because class EmployeeData is included in the same file as class Employee (employee.h). However, including the private subclass of QSharedData in the same file as the public class containing the QSharedDataPointer is not typical. Normally, the idea is to hide the private subclass of QSharedData from the user by putting it in a separate file which would not be included in the public file. In this case, we would normally put class EmployeeData in a separate file, which would not be included in employee.h. Instead, we would just predeclare the private subclass EmployeeData in employee.h this way:

I suppose compilation fails at the operator= that is used when assigning the Model.

like image 829
Kamajii Avatar asked Dec 27 '14 12:12

Kamajii


1 Answers

You have several major issues with your concept:

  • You do need to have the private class in separate files to do this nice unlike your original idea.

  • Regardless that you are writing that you used the concept of the original example from the documentation, you simply did not. You changed the copy constructor concept to copy assighment. Naturally, you need to reimplement that operator, respectively.

Here is my working example of the rewrite for the official example as I think it is better to customize that for the posterity than your diverged example to be more inline with upstream for better comprehension:

main.cpp

#include "employee.h"

int main()
{
    Employee e1(1001, "Albrecht Durer");
    Employee e2 = e1;
    Emplyoee e3;
    e3 = e2;
    e1.setName("Hans Holbein");
}

employee.h

#ifndef EMPLOYEE_H
#define EMPLOYEE_H

#include <QSharedDataPointer>
#include <QString>

class EmployeeData;
class Employee
{
  public:
    Employee();
    Employee(int id, QString name);
    Employee(const Employee &other);
    Employee& operator =(const Employee &other);
    ~Employee();
    void setId(int id);
    void setName(QString name);

    int id() const;
    QString name() const;

  private:
    QSharedDataPointer<EmployeeData> d;
};

#endif

employee_p.h

#ifndef EMPLOYEE_P_H
#define EMPLOYEE_P_H

#include <QSharedData>
#include <QString>

class EmployeeData : public QSharedData
{
  public:
    EmployeeData() : id(-1) { }
    EmployeeData(const EmployeeData &other)
        : QSharedData(other), id(other.id), name(other.name) { }
    ~EmployeeData() { }

    int id;
    QString name;
};

#endif

employee.cpp

#include "employee.h"
#include "employee_p.h"

Employee::Employee()
{
    d = new EmployeeData;
}

Employee::Employee(int id, QString name)
{
    d = new EmployeeData;
    setId(id);
    setName(name);
}

Employee::Employee(const Employee &other)
: d (other.d)
{
}

Employee& Employee::operator =(const Employee &other)
{
    d = other.d;
    return *this;
}

Employee::~Employee()
{
}

void Employee::setId(int id)
{
    d->id = id;
}

void Employee::setName(QString name)
{
    d->name = name;
}

int Employee::id() const
{
    return d->id;
}

QString Employee::name() const
{
    return d->name;
}

main.pro

TEMPLATE = app
TARGET = main
QT = core
HEADERS += employee.h employee_p.h
SOURCES += main.cpp employee.cpp
like image 126
lpapp Avatar answered Oct 07 '22 02:10

lpapp