QSharedDataPointer with forward declared class

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

So, in accordance with a small example captured in the docs, I came up with the following source (SSCCE).

Interface: Model.h

The interface is straightforward, only direct declaration of the private class and descriptor class with the declaration of copy-ctor and d-tor:

#include <QtCore/QSharedDataPointer> class ModelPrivate; class Model { public: Model(); Model(const Model &other); ~Model(); QSharedDataPointer<ModelPrivate> d; }; 

Private Title: Model_p.h

Just declares and defines the class below.

 #include <QSharedData> class ModelPrivate: public QSharedData { public: }; 

Implementation: Model.cc

It consists of the implementation of c-tors / d-tor, taken from the documents.

 #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() { } 

Example usage: main.cc

Where all this 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, like any other general class. However, it does not work well due to

 invalid use of incomplete type 'class ModelPrivate' 

I cannot figure out how to make this work in the expected way according to the documentation, i.e. without a full private class declaration in the title. I know this works in doing this, but I would like to understand the documents. An example of assigning common classes is also included in the documents. From the above documents:

The copy constructor is not strictly required here, because the EmployeeData class is included in the same file as the Employee class (Employee.h). However, including the private subclass of QSharedData in the same file as the public class containing QSharedDataPointer is not typical. The usual idea is to hide a private subclass of QSharedData from the user by placing it in a separate file that is not included in the public file. In this case, we usually put the EmployeeData class in a separate file that will not be included in employee.h. Instead, we simply provided a private subclass of EmployeeData in employee.h as follows:

I assume that compilation failed with operator= , which is used when assigning Model .

+5
source share
2 answers

You have a few basic problems with your concept:

  • You need to have a private class in separate files to make it enjoyable, unlike your original idea.

  • No matter what you write, that you used the concept of the original example from the documentation, you just did not. You changed the concept of the copy constructor to copy the assighment. Naturally, you need to redefine this operator accordingly.

Here is my working rewrite example for an official example, since I think it's better to set up for posterity than your diverging example, to be more rigorous with an upstream for a better understanding:

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 
+5
source

The problem is the operation of the member assignment operator d , which is declared and defined using the template in the QSharedDataPointer class.

The solution is as trivial as moving the assignment operator of a shared class to a module:

New interface: Model.h

 #include <QtCore/QSharedDataPointer> class ModelPrivate; class Model { public: Model(); Model(const Model &other); Model &operator =(const Model &other); /* <-- */ ~Model(); QSharedDataPointer<ModelPrivate> d; }; 

Private Title: Model_p.h

 #include <QSharedData> class ModelPrivate: public QSharedData { public: }; 

Implementation: Model.cc:

 #include "Model.h" #include "Model_p.h" Model::Model(): d(new ModelPrivate()) { } Model::Model(const Model &other): d(other.d) { } Model::~Model() { } Model &Model::operator =(const Model &other) { d = other.d; return *this; } 

Example usage: main.cc

 #include <QString> #include "Model.h" int main() { QString s1, s2; s2 = s1; Model m1, m2; m2 = m1; } 

Project File: example.pro

 TEMPLATE = app TARGET = example QT = core HEADERS += Model.h Model_p.h SOURCES += Model.cc main.cc 

Actually, this is how other classes are implemented in the very youth of Qt. For example, consider a QTextCursor .

0
source

Source: https://habr.com/ru/post/1209956/


All Articles