Название: Абстрактные класс и виртуальные операторы (присваивание и сравнение)
Отправлено: Fregloin от Март 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 вызывался соответствующий оператор присваивания/сравнения?
Название: Re: Абстрактные класс и виртуальные операторы (присваивание и сравнение)
Отправлено: m_ax от Март 26, 2012, 14:40
Вобщем все вычисления состояния объекта производятся в виртуальной функции calcState(). В функцию update(..) для кадого класса передается соотвествующее ему состояние (как показано выше). Можно ли сделать операторы присваивания и сравнения виртуальными? что бы сравенение наследников было корректным? Т.е. что бы для состояний CLightState вызывался соответствующий оператор присваивания/сравнения?
Это очень странное желание) Какой смысл определять виртуальный оператор присваивания в базовом, чисто абстрактном классе? Вы всё равно не сможете создать объект этого класса. Или я чего то не так понял?
Название: Re: Абстрактные класс и виртуальные операторы (присваивание и сравнение)
Отправлено: Igors от Март 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; };
Название: Re: Абстрактные класс и виртуальные операторы (присваивание и сравнение)
Отправлено: Fregloin от Март 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(); } }
Все работает как надо, но вот соменваюсь в плане производительности, так как объектов с такими состояниями довольно много и зачастую их приходится многократно обновлять (при поступающих изменениях с сервера).
Название: Re: Абстрактные класс и виртуальные операторы (присваивание и сравнение)
Отправлено: Fregloin от Март 27, 2012, 09:18
собственно для чего все это делаю: раньше состояния объектов задавалось простыми битовыми масками (которые приходили с сервера в виде quint32), но с переходом на другой протокол возникла необходимость расширить функционал состояний из простого беззнакового числа в осмысленные объекты со своими полями для каждого типа устройства/объекта.
Название: Re: Абстрактные класс и виртуальные операторы (присваивание и сравнение)
Отправлено: popper от Март 27, 2012, 13:57
Можно отказаться от использования dynamic_cast, например, используя подход, который реализован в qgraphicsitem_cast.
В текущей реализации все классы подходят под критерий "assignable data type", поэтому операцию копирования можно переложить на предоставляемый компилятором дефолтовый оператор.
Может быть, в архитектуру данного проекта хорошо впишется модель неявного совместного использования данных (смотри QSharedDataPointer).
Название: Re: Абстрактные класс и виртуальные операторы (присваивание и сравнение)
Отправлено: Fregloin от Март 28, 2012, 14:13
на счёт shared pointer - проблема в том, что я получаю данные по двум каналам с двух серверов, а потом по определенному алгоритму выдаю результирующие состояния (либо с первого либо со второго)
Название: Re: Абстрактные класс и виртуальные операторы (присваивание и сравнение)
Отправлено: Igors от Март 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; }
|