Разрешение циклической зависимости в шаблоне состояний с помощью C ++ - PullRequest
2 голосов
/ 04 марта 2011

Я пытаюсь реализовать шаблон состояния в C ++, но возникают проблемы с циклической зависимостью.Я прочитал другой связанный материал здесь - к сожалению, это не помогло мне.У меня нет большого опыта работы с C ++, так что терпите меня.Следующий код разработан на компьютере с Ubuntu 10.10 в Eclipse Helios CDT:

ConcreteSystem.h

#ifndef CONCRETESYSTEM_H_
#define CONCRETESYSTEM_H_

class SystemState;

class ConcreteSystem {
public:
    ConcreteSystem();
    void SelfTestFailed();
    void Restart();
private:
    friend class SystemState;
    SystemState *currentState;
    void ChangeState(SystemState *state);
};

#endif /* CONCRETESYSTEM_H_ */

ConcreteSystem.cpp

#include "ConcreteSystem.h"
#include "SystemState.h"

ConcreteSystem::ConcreteSystem() {
    currentState = SelfTest::GetInstance();
}

void ConcreteSystem::SelfTestFailed() {
    currentState->SelfTestFailed(this);
}

void ConcreteSystem::Restart() {
    currentState->Restart(this);
}

void ConcreteSystem::ChangeState(SystemState *state){
    currentState = state;
}

SystemState.h

#ifndef SYSTEMSTATE_H_
#define SYSTEMSTATE_H_

class ConcreteSystem;

class SystemState {
public:
    virtual void Restart(ConcreteSystem *cs);
    virtual void SelfTestFailed(ConcreteSystem *cs);
protected:
    virtual void ChangeState(ConcreteSystem *cs, SystemState *state);
};

#endif /* SYSTEMSTATE_H_ */

SystemState.cpp

#include "SystemState.h"
#include "ConcreteSystem.h"

void SystemState::Restart(ConcreteSystem *cs) {

}

void SystemState::SelfTestFailed(ConcreteSystem *cs) {

}


void SystemState::ChangeState(ConcreteSystem *cs, SystemState *state) {
    cs->ChangeState(state);
}

SelfTest.h

#ifndef SELFTEST_H_
#define SELFTEST_H_

#include "SystemState.h"


class SelfTest : public SystemState {
public:
    SelfTest();
    void SelfTestFailed(ConcreteSystem* cs);
    static SystemState* GetInstance();
private:
    static SystemState* instance;
};

#endif /* SELFTEST_H_ */

SelfTest.cpp

#include "SelfTest.h"
#include "Failure.h"

SystemState* SelfTest::instance = 0;

SelfTest::SelfTest() {

}

void SelfTest::SelfTestFailed(ConcreteSystem *cs) {
    ChangeState(cs, Failure::GetInstance());
}

SystemState* SelfTest::GetInstance() {
    if (instance == 0) {
        instance = new SelfTest();
    }
    return instance;
}

Failure.h

#ifndef FAILURE_H_
#define FAILURE_H_

#include "SystemState.h"

class SelfTest;

class Failure : public SystemState {
public:
    Failure();
    void Restart(ConcreteSystem* t);
    static SystemState* GetInstance();
private:
    static SystemState* instance;
};

#endif /* FAILURE_H_ */

Failure.cpp

#include "Failure.h"
#include "SelfTest.h"

SystemState* Failure::instance = 0;

Failure::Failure() {

}

void Failure::Restart(ConcreteSystem* t) {
    ChangeState(t, SelfTest::GetInstance());
}

SystemState* Failure::GetInstance() {
    if (instance == 0) {
        instance = new Failure();
    }
    return instance;
}

У меня проблема с включениями, из-за которых возникают странные ошибки компилятора.Кто-нибудь с хорошим решением этой проблемы?

1 Ответ

3 голосов
/ 04 марта 2011

Судя по написанному вами коду, у вас будут переопределяться классы. Глядя на ваш файл Failure.cpp, вы получаете:

#include "Failure.h"
#include "SelfTest.h"

Который будет включать оба этих файла, и каждый из этих файлов включает файл SystemState.h. Поскольку файл SystemState.h включен более одного раза, он пытается переопределить класс SystemState. В верхней части каждого из ваших заголовочных файлов вы должны сделать что-то вроде этого:

// SystemState.h
#ifndef SystemState_h
#define SystemState_h
.. class definition ..
#endif // close the if statement from above.

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

Кроме того, если вы относительно неопытны в C ++, я бы рекомендовал рассматривать этот как отличный источник учебного материала (в дополнение к StackOverflow, конечно!).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...