QSharedDataPointer с объявленным вперед классом

документация Qt предлагает использовать QSharedDataPointer с видимой реализацией его низшее нетипично.

Итак, в соответствии с небольшим примером, вырезанным из документации, я придумал следующий источник (SSCCE).

Интерфейс: Model.h

Интерфейс прост, просто предварительное объявление частного класса и класса дескриптора с объявленными copy-ctor и d-tor:

#include <QtCore/QSharedDataPointer>

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

        QSharedDataPointer<ModelPrivate> d;
};

Частный заголовок: Model_p.h

Просто объявляет и определяет низший класс.

#include <QSharedData>
class ModelPrivate:
    public QSharedData {

    public:

};

Реализация: Model.cc

Состоит из реализации c-tors/d-tor, взятой из документации.

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

}

Вариант использования: main.cc

Где все провалилось.

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

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

    Model m1, m2;
    m2 = m1;
}

Всего два экземпляра и присваивание, как и для любого другого общего класса. Однако он терпит неудачу из-за

invalid use of incomplete type 'class ModelPrivate'

Я не могу понять, как заставить это работать ожидаемым образом в соответствии с документацией, то есть без полного объявления частного класса в заголовке. Я знаю, что это работает, но я хотел бы понять документы. Пример назначения общих классов также включен в документы. Из документов, указанных выше:

Конструктор копирования здесь строго не требуется, поскольку класс EmployeeData включен в тот же файл, что и класс Employee (employee.h). Однако включение частного подкласса QSharedData в тот же файл, что и общедоступный класс, содержащий QSharedDataPointer, не является типичным. Обычно идея состоит в том, чтобы скрыть частный подкласс QSharedData от пользователя, поместив его в отдельный файл, который не будет включен в общедоступный файл. В этом случае мы обычно помещаем класс EmployeeData в отдельный файл, который не включается в employee.h. Вместо этого мы бы просто предварительно объявили частный подкласс EmployeeData в файле employee.h следующим образом:

Я предполагаю, что компиляция завершается ошибкой в ​​operator=, который используется при назначении Model.


person Kamajii    schedule 27.12.2014    source источник
comment
Не пробовал, но поскольку никто не указал на это: вы уверены, что вам просто не нужно реализовывать operator= для своего класса, вместо того, чтобы позволить компилятору сгенерировать его?   -  person peppe    schedule 27.12.2014


Ответы (2)


У вас есть несколько основных проблем с вашей концепцией:

  • Вам нужно иметь частный класс в отдельных файлах, чтобы сделать это хорошо, в отличие от вашей первоначальной идеи.

  • Вне зависимости от того, что вы пишете, что использовали концепцию оригинального примера из документации, вы просто этого не сделали. Вы изменили концепцию конструктора копирования на присваивание копии. Естественно, вам нужно переопределить этот оператор, соответственно.

Вот мой рабочий пример переписывания официального примера, поскольку я думаю, что лучше настроить его для потомков, чем ваш отклоняющийся пример, чтобы он был более встроенным в восходящий поток для лучшего понимания:

main.cpp

#include "employee.h"

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

сотрудник.ч

#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

сотрудник.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
person lpapp    schedule 27.12.2014

Проблема на самом деле заключается в операторе присваивания члена d, который объявлен и определен через шаблон в классе QSharedDataPointer.

Решение такое же тривиальное, как перемещение оператора присваивания общего класса в модуль:

Новый интерфейс: Model.h

#include <QtCore/QSharedDataPointer>

class ModelPrivate;
class Model {
    public:
        Model();
        Model(const Model &other);
        Model &operator =(const Model &other); /* <-- */
        ~Model();

        QSharedDataPointer<ModelPrivate> d;
};

Частный заголовок: Model_p.h

#include <QSharedData>
class ModelPrivate:
    public QSharedData {

    public:

};

Реализация: 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;
}

Вариант использования: main.cc

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

int main() {
    QString s1, s2;
    s2 = s1;

    Model m1, m2;
    m2 = m1;
}

Файл проекта: example.pro

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

На самом деле это то, как реализованы другие классы в самой вселенной Qt. Например, рассмотрим QTextCursor.

person Kamajii    schedule 27.12.2014