Russian Qt Forum
Ноябрь 23, 2024, 15:48 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Абстрактные класс и виртуальные операторы (присваивание и сравнение)  (Прочитано 8840 раз)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« : Март 26, 2012, 14:31 »

Привет, можно ли реализовать следующее?
Есть много классов объектов, у которых есть общий предок.
У каждого класса есть свое состояние объекта (по сути набор булевых или целочесленных значений). Для каждого класса этот набор отличается, но есть и общие значения.
Я определил базовый класс состояния так:
Код:
class CAbstractState
{
public:
    enum ContactState {csUnknown=-1,csOff,csOn,csBlink};    //состояние "контакта"
    CAbstractState();
    virtual void    disable()=0;    //установка неактивного состояния
    virtual void    enable()=0;     //установка активного состояния по умолчанию
    virtual void    clear()=0;      //инициализация
    bool            changed;        //признак изменения состояния на сервере
};
Затем для базового класса объявил наследника
Код:
class CRailObjectState : public CAbstractState
{
public:
    CRailObjectState();

    ContactState    error;      //признак ошибки
    ContactState    block;      //признак блокировки

    void            disable();
    void            enable();
    void            clear();

    CRailObjectState    &operator=(const CRailObjectState & state);
    bool                operator==(const CRailObjectState & state);
    bool                operator!=(const CRailObjectState & state);
};

Код:
CRailObjectState &CRailObjectState::operator =(const CRailObjectState &state)
{
    if(this!=&state)
    {
        error = state.error;
        block = state.block;
    }
    return  *this;
}

bool CRailObjectState::operator==(const CRailObjectState &state)
{
    return (error==state.error) && (block==state.block);
}

bool CRailObjectState::operator!=(const CRailObjectState &state)
{
    return  !(*this==state);
}

и к примеру еще одни наследник для конкретного типа объекта
Код:
class CLightState : public CRailObjectState
{
public:
    CLightState();

    ContactState    manevrSignal;
    ContactState    trainSignal;
    ContactState    inviteSignal;
    ContactState    blueSignal;
    ContactState    ngState;
    ContactState    lampFail;

    void    disable();
    void    enable();
    void    clear();

    CLightState &operator=(const CLightState & state);
    bool        operator ==(const CLightState & state);
    bool        operator !=(const CLightState & state);

    void        setDeined();
    void        setAllowManevr();
    void        setAllowTrain();

    bool        isDenied();
};

Код:
CLightState &CLightState::operator =(const CLightState &state)
{
    if(this!=&state)
    {
        this->error = state.error;
        this->block = state.block;
        this->manevrSignal = state.manevrSignal;
        this->trainSignal = state.trainSignal;
        this->inviteSignal = state.inviteSignal;
        this->blueSignal = state.blueSignal;
        this->ngState = state.ngState;
        this->commandK = state.commandK;
        this->commandMk = state.commandMk;
        this->commandKm = state.commandKm;
        this->releK = state.releK;
        this->releMk = state.releMk;
        this->releKm = state.releKm;
    }
    return  *this;
}

bool CLightState::operator ==(const CLightState &state)
{
    return  (this->error == state.error) &&
            (this->block == state.block) &&
            (this->manevrSignal == state.manevrSignal) &&
            (this->trainSignal == state.trainSignal) &&
            (this->inviteSignal == state.inviteSignal) &&
            (this->blueSignal == state.blueSignal) &&
            (this->ngState == state.ngState) &&
            (this->commandK == state.commandK) &&
            (this->commandMk == state.commandMk) &&
            (this->commandKm == state.commandKm) &&
            (this->releK == state.releK) &&
            (this->releMk == state.releMk) &&
            (this->releKm == state.releKm);
}

bool CLightState::operator !=(const CLightState & state)
{
    return !(*this==state);
}

Базовый класс объектов (очень урезанный)
Код:
class CRailObject   :   public  QObject, public CXMLSerialisationObject
{
    Q_OBJECT

    CRailObjectState    *   fobjectState;   //состояние объекта
explicit    CRailObject(CEC *   ParentEC);
    ~CRailObject();

void                update(CRailObjectState *   State);
virtual     bool    calcState() = 0;                //вычислить состояние
}
Вобщем все вычисления состояния объекта производятся в виртуальной функции calcState().
В функцию update(..) для кадого класса передается соотвествующее ему состояние (как показано выше).
Можно ли сделать операторы присваивания и сравнения виртуальными? что бы сравенение наследников было корректным?
Т.е. что бы для состояний CLightState вызывался соответствующий оператор присваивания/сравнения?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #1 : Март 26, 2012, 14:40 »

Цитировать
Вобщем все вычисления состояния объекта производятся в виртуальной функции calcState().
В функцию update(..) для кадого класса передается соотвествующее ему состояние (как показано выше).
Можно ли сделать операторы присваивания и сравнения виртуальными? что бы сравенение наследников было корректным?
Т.е. что бы для состояний CLightState вызывался соответствующий оператор присваивания/сравнения?
Это очень странное желание)
Какой смысл определять виртуальный оператор присваивания в базовом, чисто абстрактном классе?
Вы всё равно не сможете создать объект этого класса.  

Или я чего то не так понял?
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Март 26, 2012, 14:49 »

Сами операторы нельзя, но можно через виртуальную ф-цию

Код
C++ (Qt)
class CBase {
bool operator == ( const CBase & sec ) const { return IsSame(sec); }
virtual bool IsSame( const CBase & sec ) const = 0;
};
 
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #3 : Март 27, 2012, 09:14 »

Решил сделать так:
Определил в базовом абстрактном классе две функции - сравнение и присваивание
Код:
class CAbstractState
{
public:
    enum ContactState {csUnknown=-1,csOff,csOn,csBlink};    //состояние "контакта"
    CAbstractState();
    virtual void    disable()=0;    //установка неактивного состояния
    virtual void    enable()=0;     //установка активного состояния по умолчанию
    virtual void    clear()=0;      //инициализация
    bool            changed;        //признак изменения состояния на сервере
    virtual bool    isEqualTo(CAbstractState * state)=0;  //возвращает true если все поля состояния идентичны
    virtual void    assign(CAbstractState * state)=0;     //копирует состояние
};

Вот как сделано в наследниках (все приводить не буду, их порядка 10)
Код:
class CRailObjectState : public CAbstractState
{
public:
    CRailObjectState();

    ContactState    error;      //признак ошибки
    ContactState    block;      //признак блокировки

    void            disable();
    void            enable();
    void            clear();

    bool            isEqualTo(CAbstractState *state);
    void            assign(CAbstractState *state);

};

...

bool CRailObjectState::isEqualTo(CAbstractState *state)
{
    if(this==state)
        return true;

    CRailObjectState    *   fromWhat = dynamic_cast<CRailObjectState*>(state);
    if(fromWhat)
    {
        return (this->block == fromWhat->block) && (this->error == fromWhat->error);
    }
    else
        throw CAbstractStateException();
    return  false;
}

void CRailObjectState::assign(CAbstractState *state)
{
    if(this!=state)
    {
        CRailObjectState    *   fromWhat = dynamic_cast<CRailObjectState*>(state);
        if(fromWhat)
        {
            this->block = fromWhat->block;
            this->error = fromWhat->error;
        }
        else
            throw CAbstractStateException();
    }
}

Код:
class CLightState : public CRailObjectState
{
public:
    CLightState();

    ContactState    manevrSignal;
    ContactState    trainSignal;
    ContactState    inviteSignal;
    ContactState    blueSignal;
    ContactState    ngState;
    ContactState    lampFail;

...
    bool        isEqualTo(CAbstractState *state);
    void        assign(CAbstractState *state);

};


bool CLightState::isEqualTo(CAbstractState *state)
{
    if(this==state)
        return true;
    CLightState * fromWhat = dynamic_cast<CLightState*>(state);
    if(fromWhat)
    {
        return  CRailObjectState::isEqualTo(fromWhat) &&
                (this->manevrSignal == fromWhat->manevrSignal) &&
                (this->trainSignal == fromWhat->trainSignal) &&
                (this->inviteSignal == fromWhat->inviteSignal) &&
                (this->blueSignal == fromWhat->blueSignal) &&
                (this->ngState == fromWhat->ngState) &&
                (this->commandK == fromWhat->commandK) &&
                (this->commandMk == fromWhat->commandMk) &&
                (this->commandKm == fromWhat->commandKm) &&
                (this->releK == fromWhat->releK) &&
                (this->releMk == fromWhat->releMk) &&
                (this->releKm == fromWhat->releKm);
    }
    else
        throw CAbstractStateException();
    return  false;
}

void CLightState::assign(CAbstractState *state)
{
    CRailObjectState::assign(state);
    if(this!=state)
    {
        CLightState * fromWhat = dynamic_cast<CLightState*>(state);
        if(fromWhat)
        {
            this->manevrSignal = fromWhat->manevrSignal;
            this->trainSignal = fromWhat->trainSignal;
            this->inviteSignal = fromWhat->inviteSignal;
            this->blueSignal = fromWhat->blueSignal;
            this->ngState = fromWhat->ngState;
            this->commandK = fromWhat->commandK;
            this->commandMk = fromWhat->commandMk;
            this->commandKm = fromWhat->commandKm;
            this->releK = fromWhat->releK;
            this->releMk = fromWhat->releMk;
            this->releKm = fromWhat->releKm;
        }
        else
            throw CAbstractStateException();
    }
}
Все работает как надо, но вот соменваюсь в плане производительности, так как объектов с такими состояниями довольно много и зачастую их приходится многократно обновлять (при поступающих изменениях с сервера).
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #4 : Март 27, 2012, 09:18 »

собственно для чего все это делаю: раньше состояния объектов задавалось простыми битовыми масками (которые приходили с сервера в виде quint32), но с переходом на другой протокол возникла необходимость расширить функционал состояний из простого беззнакового числа в осмысленные объекты со своими полями для каждого типа устройства/объекта.
Записан
popper
Гость
« Ответ #5 : Март 27, 2012, 13:57 »

Можно отказаться от использования dynamic_cast, например, используя подход, который реализован в qgraphicsitem_cast.

В текущей реализации все классы подходят под критерий "assignable data type", поэтому операцию копирования можно переложить на предоставляемый компилятором дефолтовый оператор.

Может быть, в архитектуру данного проекта хорошо впишется модель неявного совместного использования данных (смотри QSharedDataPointer).
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #6 : Март 28, 2012, 14:13 »

на счёт shared pointer - проблема в том, что я получаю данные по двум каналам с двух серверов, а потом по определенному алгоритму выдаю результирующие состояния (либо с первого либо со второго)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Март 28, 2012, 14:35 »

Не вижу никаких оснований для тормозов в этом месте. Не вижу зачем нужен assign, вроде дефаултный должен устроить. А причесать сравнение можно так
Код
C++ (Qt)
// определяете оператор(ы) с традиционной ориентацией
bool CLightState::operator == ( const CLightState:& sec ) const
{
     return  (CRailObjectState &) *this == sec) &&
               (this->manevrSignal == sec->manevrSignal) &&
               (this->trainSignal == sec->trainSignal) &&
               ....
}
 
// разгружаете isEqualTo
bool CLightState::isEqualTo(CAbstractState *state)
{
   if(this == state)  return true;
   CLightState * sec = dynamic_cast<CLightState*>(state);
   iif (sec) return *this == *sec;
   throw CAbstractStateException();
   return  false;
}
 
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.099 секунд. Запросов: 22.