Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > [Qt]Перегрузка оператора


Автор: aspirin2003 21.7.2008, 10:14
Извиняюсь что не совсем в тему, но все же...
В общем создаю класс, наследуя его от QObject, например:
Код

#ifndef CALCELEMENT_H
#define CALCELEMENT_H

#include <QObject>
#include <QStringList>

class CalcElement : public QObject
{
    Q_OBJECT

public:
    CalcElement(QObject *parent);
    ~CalcElement();
    CalcElement operator + (CalcElement &m1);

private:
    double dd;
    
};

#endif // CALCELEMENT_H

Код

#include "calcelement.h"

CalcElement::CalcElement(QObject *parent)
    : QObject(parent)
{
    this->dd = 100;
}

CalcElement::~CalcElement()
{

}

CalcElement CalcElement::operator +(CalcElement &m1)
{
    CalcElement res(NULL);
    res.dd = dd + m1.dd;
    return res;
}

и пытаюсь перегрузить в нем оператор '+'

Проверяю так:
Код

    CalcElement elem(NULL);
    CalcElement elem1(NULL);
    CalcElement elem2 = elem + elem1;


Но выскакивает ошибка:
error C2248: 'QObject::QObject' : cannot access private member declared in class 'QObject'

Если же не наследоваться от QObject, то все ok. 


Автор: anatox91 21.7.2008, 10:18
Цитата(aspirin2003 @  21.7.2008,  10:14 Найти цитируемый пост)
res.dd = dd + m1.dd;

у тебя же dd - private

Автор: aspirin2003 21.7.2008, 11:07
Цитата(anatox91 @ 21.7.2008,  10:18)
Цитата(aspirin2003 @  21.7.2008,  10:14 Найти цитируемый пост)
res.dd = dd + m1.dd;

у тебя же dd - private

Ну и что? dd используется внутри класса CalcElement, и доступен его методам. Дело не в этом, я думаю
P.S. На всякий случай проверил, сделал public - ничего не изменилось

Автор: anatox91 21.7.2008, 11:16
aspirin2003, тю блин, сорри, забыл что это мембер

Автор: SABROG 21.7.2008, 11:19
Попробуй использовать вместо dd другое имя, обычно имена и dd используются в приватных классах Qt. Попробуй так изменить:

Код

res.dd = CalcElement::dd + m1.dd;

Автор: anatox91 21.7.2008, 11:20
*deleted*

Автор: SABROG 21.7.2008, 11:23
Цитата(anatox91 @ 21.7.2008,  11:20)
*deleted*

Да нет, только [] и то где-то в QObjectPrivate.

Автор: aspirin2003 21.7.2008, 11:36
Цитата(SABROG @ 21.7.2008,  11:19)
Попробуй использовать вместо dd другое имя, обычно имена и dd используются в приватных классах Qt. Попробуй так изменить:

Код

res.dd = CalcElement::dd + m1.dd;

Нет, эта строка вообще не влияет на ошибку. Даже если ее закомментировать и возвращать NULL, то ничего не меняется.
Насколько я понял, ошибка возникает здесь: 
Код

   CalcElement res(NULL);


P.S. На всякий случай изменять имя на другое пробовал, не помогает

Автор: SABROG 21.7.2008, 12:08
В общем дело обстоит так. Конструктор копирования у классов на базе QObject переопределен таким образом, чтобы запретить эту операцию. Существует макрос Q_DISABLE_COPY:

Код

#if !defined(Q_NO_DECLARED_NOT_DEFINED) || !defined(QT_MAKEDLL)
 #define Q_DISABLE_COPY(Class) \
     Class(const Class &); \
     Class &operator=(const Class &);
#else
 #define Q_DISABLE_COPY(Class)
#endif


Который прописан в секции private QObject'a:

Код

protected:
    QObjectData *d_ptr;

    static const QMetaObject staticQtMetaObject;

    friend struct QMetaObject;
    friend class QApplication;
    friend class QApplicationPrivate;
    friend class QCoreApplication;
    friend class QCoreApplicationPrivate;
    friend class QWidget;
    friend class QThreadData;

private:
    Q_DISABLE_COPY(QObject)
    Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *))
};



Может быть возможно переопределить конструктор копирования в своем классе и оператор =, но не известно к чему это может привести.

Автор: aspirin2003 21.7.2008, 12:55
Цитата(SABROG @ 21.7.2008,  12:08)
Может быть возможно переопределить конструктор копирования в своем классе и оператор =, но не известно к чему это может привести.

Моих знаний по C++ врядли хватит чтобы самому с этим разобраться :(
Возможно ли решить проблему другим способом? Ведь перегрузка операторов в классе - достаточно распространенное явление

P.S. Сделал так:
Код

CalcElement::CalcElement(const CalcElement& c_el)
{
    dd = c_el.dd;
}


Теперь вроде работает, но прочитал в одной статейке, что "...Переопределение конструктора копирования является чрезвычайно ответственным поступком. Явное определение конструктора копирования вызывает изменения в работе программы..."

Теперь еще вопрос - надо ли в конструкторе копирования что-либо делать с методами класса, или делать только копирование его полей?

Автор: SABROG 21.7.2008, 13:42
Конструктор копирования, что идет по-умолчанию сам копирует поля с данными. К методам это никак не относится, код методов один для всех экземпляров класса один, если только это не шаблон класса, где под каждый тип генерятся методы.

Кстати интересно возможно ли вызвать дефолтный конструктор копирования ?:

Код

CalcElement::CalcElement(const CalcElement& c_el)
{
    CalcElement::CalcElement(c_el);
}


Или возникнет рекурсия ?

А вообще конструкторов 2:

CalcElement::CalcElement(const CalcElement& c_el)
CalcElement::CalcElement(CalcElement& c_el)

Автор: aspirin2003 21.7.2008, 14:23
Цитата(SABROG @ 21.7.2008,  13:42)
Кстати интересно возможно ли вызвать дефолтный конструктор копирования ?:

Код

CalcElement::CalcElement(const CalcElement& c_el)
{
    CalcElement::CalcElement(c_el);
}


Или возникнет рекурсия ?

Не знаю насчет рекурсии, но Access violation точно возникает

Автор: SABROG 21.7.2008, 14:27
Потому что стек заканчивается на возврат. Т.е. рекурсия идет.

Автор: aspirin2003 21.7.2008, 16:13
Всем спасибо за ответы, особенно SABROG

Автор: aspirin2003 24.7.2008, 09:04
Теперь в коде:
Код

CalcElement res(NULL);
CalcElement item_1(NULL);
CalcElement item_2(NULL);
...
res = item_1 + item_2;

 вылазит ошибка
error C2248: 'QObject::operator =' : cannot access private member declared in class 'QObject'
Насколько я понял теперь еще нужно переопределить оператор '='.  Как это лучше сделать - копированием полей как в конструкторе копирования, или есть какой-то более оптимальный способ, чтобы не тратить время на перемещение данных в памяти?

P.S. Тем более как выяснилось, простое копирование полей не прокатывает :(
Делаю:
Код

CalcElement CalcElement::operator =(CalcElement &m1)
{
    CalcElement res(NULL);
    res.mask = m1.mask;
    res.tuple = m1.tuple;
    res.maskLen = m1.maskLen;
    res.tupleLen = m1.tupleLen;
    return res;
}


В res вроде все как надо, а возвращаемый на самом деле объект в полях содержит какую-то чушь.
Скорее всего надо как-то по-другому делать, а как именно я не знаю. Помогите пожалуйста!

Автор: aspirin2003 24.7.2008, 16:36
В общем заработало когда переопределил так:
Код

void CalcElement::operator =(CalcElement &m1)
{
    this->mask = m1.mask;
    this->tuple = m1.tuple;
    this->maskLen = m1.maskLen;
    this->tupleLen = m1.tupleLen;
}

 Однако мне кажется что это не лучший способ (данные перемещаются из одной области памяти в другую).
 Может есть какой-нибудь способ передачи по указателю/ссылке?

Автор: SABROG 24.7.2008, 17:30
Цитата(aspirin2003 @  24.7.2008,  16:36 Найти цитируемый пост)
данные перемещаются из одной области памяти в другую


Т.е. если позволить компилятору присваивать данные за тебя, то перемещения данных из одной области памяти в другую не будет ;) ? Посмотри как в Qtшных классах реализован алгоритм  "implicit sharing (copy-on-write)" и сделай также если хватит знаний.

Автор: Любитель 24.7.2008, 19:01
Цитата(SABROG @  24.7.2008,  17:30 Найти цитируемый пост)
Посмотри как в Qtшных классах реализован алгоритм  "implicit sharing (copy-on-write)" и сделай также если хватит знаний. 

Там реализовано через свои макросы, но предоставляется ready to use класс QImplicitSharedDataPointer (может в названии чуть ошибся). С подробным и простым how to use it. Главное консты расставлять на методах - иначе вдобавок к COW будет COR (Copy on reading) smile

Автор: SABROG 24.7.2008, 20:13
Асистент вроде не находит. Нашел только QAtomicInt и QAtomicPointer, но пока не понял их предназначение.

Автор: aspirin2003 25.7.2008, 08:59
Цитата(SABROG @ 24.7.2008,  17:30)
Посмотри как в Qtшных классах реализован алгоритм  "implicit sharing (copy-on-write)" и сделай также если хватит знаний.

Прочитал статью http://doc.trolltech.com/qq/qq02-data-sharing-with-class.html. Круто придумано, нечего сказать smile

Автор: SABROG 25.7.2008, 11:10
Так, значит речь идет http://doc.trolltech.com/4.4/qshareddata.html, http://doc.trolltech.com/4.4/qshareddatapointer.html и http://doc.trolltech.com/4.4/qsharedmemory.html, и http://doc.trolltech.com/4.4/qexplicitlyshareddatapointer.html

Народ, поздравлю всех с Днем Системного Администратора

Автор: Любитель 25.7.2008, 14:06
Цитата(SABROG @  25.7.2008,  11:10 Найти цитируемый пост)
QSharedDataPointer 

Ну да, писал по памяти - ошибся smile

Автор: aspirin2003 26.7.2008, 18:25
Цитата(Любитель @ 24.7.2008,  19:01)
Главное консты расставлять на методах - иначе вдобавок к COW будет COR (Copy on reading) smile

Но только в случае, когда методы не модифицируют данные, так?

Автор: anatox91 26.7.2008, 19:02
aspirin2003, ну если модифицируют, то можно сделать эти данные mutable, но все конечно зависит от ситуации

Автор: aspirin2003 27.7.2008, 10:47
Попробовал переписал класс с использованием QSharedData. Вот примерно то, что получилось:
calcelement.h
Код

#ifndef CALCELEMENT_H
#define CALCELEMENT_H

#include <QObject>
#include <QSharedData>
#include <QStringList>
#include <QVector>

typedef QVector<int> matr_row;
typedef QVector<matr_row> matrix_double;

class CalcElementData : public QSharedData
{
public:
    CalcElementData() {}
    CalcElementData(const CalcElementData &other) : QSharedData(other) {}
    ~CalcElementData() {}
    QStringList tuple;
    matrix_double mask;
    int tupleLen;
    int maskLen;
};

class CalcElement : public QObject
{
    Q_OBJECT

public:
    CalcElement(QObject *parent);
    CalcElement(const CalcElement& c_el);
    CalcElement(CalcElement& c_el);
    ~CalcElement();
    CalcElement operator + (CalcElement &m1);
    void operator = (CalcElement &m1);
    void operator += (CalcElement &m1);

private:
    QSharedDataPointer<CalcElementData> d;

};

#endif // CALCELEMENT_H


calcelement.cpp
Код

#include "calcelement.h"

CalcElement::CalcElement(QObject *parent)
    : QObject(parent)
{
    d = new CalcElementData;
}

CalcElement::~CalcElement()
{
}

CalcElement CalcElement::operator +(CalcElement &m1)
{
    CalcElement res(NULL);
    /*код*/
    return res;
}

void CalcElement::operator +=(CalcElement &m1)
{
    CalcElement res(NULL);
    res = *this + m1;
    d = res.d;
}

void CalcElement::operator =(CalcElement &m1)
{
    d = m1.d;
}


CalcElement::CalcElement(const CalcElement& c_el)
{
    d = c_el.d;
}

CalcElement::CalcElement(CalcElement& c_el)
{
    d = c_el.d;
}



MSVC этот код компилит нормально, все работает. А gcc ругается в этой строке:
Код

res = *this + m1;

no match for 'operator=' in 'res = CalcElement::operator+(CalcElement&)(((CalcElement&)(+m1)))'    calcelement.cpp    

Помогите пожалуйста разобраться, в чем косяк.

Автор: aspirin2003 27.7.2008, 19:39
Ни у кого никаких соображений? Просто надо чтобы программа работала и под Linux тоже, а gcc ругается :(

Автор: nickless 28.7.2008, 21:14
aspirin2003, типы операторам надо давать не какие попало, а какие положено smile 

*.h
Код

#include <QObject>
#include <QSharedData>
#include <QStringList>
#include <QVector>

typedef QVector<int> matr_row;
typedef QVector<matr_row> matrix_double;

class CalcElementData : public QSharedData
{
public:
    CalcElementData() {}
    CalcElementData(const CalcElementData &other) : QSharedData(other) {}
    ~CalcElementData() {}
    QStringList tuple;
    matrix_double mask;
    int tupleLen;
    int maskLen;
};
class CalcElement : public QObject
{
    Q_OBJECT
public:
    CalcElement(QObject *parent);
    CalcElement(const CalcElement& c_el);
    ~CalcElement();
    CalcElement operator+ (const CalcElement &m1);
    CalcElement & operator= (const CalcElement &m1);
    CalcElement & operator+= (const CalcElement &m1);
private:
    QSharedDataPointer<CalcElementData> d;
};
#endif // CALCELEMENT_H


*.cpp
Код

#include "calcelement.h"
CalcElement::CalcElement(QObject *parent)
    : QObject(parent)
{
    d = new CalcElementData;
}

CalcElement::CalcElement(const CalcElement& c_el)
    : QObject(c_el.parent())
{
    d = c_el.d;
}

CalcElement::~CalcElement()
{
}

CalcElement CalcElement::operator +(const CalcElement &m1)
{
    CalcElement res(NULL);
    /*код*/
    return res;
}

CalcElement & CalcElement::operator +=(const CalcElement &m1)
{
    CalcElement res(NULL);
    res = *this + m1;
    d = res.d;
    return *this;
}

CalcElement & CalcElement::operator =(const CalcElement &m1)
{
    d = m1.d;
    return *this;
}

Автор: aspirin2003 29.7.2008, 15:17
nickless Спасибо! Все заработало!

Автор: WizardNG 26.7.2019, 14:59
удалено

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)