преобразование нормального члена класса в статический член класса - PullRequest
1 голос
/ 19 ноября 2010

Я создаю «систему», чтобы потом можно было писать в «среде действия». Я хочу дать своему экземпляру (то есть «машине») определенное состояние (то есть парковка, вождение, запуск). Затем во время какого-либо события он должен выполнить код в зависимости от состояния.

Я не хочу использовать оператор switch / if-then-else, поскольку он очень ошибочен и его трудно расширить. (Чтобы учесть больше государств). Вместо этого я хочу использовать указатели на функции.

Код, который у меня есть (игнорируйте глупости функций, которые они должны продемонстрировать):

#define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember)) 
enum State {Set, Add, Mul};
class car {
public:
    typedef void (car::*MemFn)(int v);
    car(int v, State _s) : val(v), s(_s) {
        posFunctions.insert(std::make_pair(State(Set),&car::SetVal));
        posFunctions.insert(std::make_pair(State(Add),&car::AddVal));
    }
    void DoIt(int v) {
        //MemFn t = &car::SetVal;
        MemFn t = posFunctions.find(s)->second;
        CALL_MEMBER_FN(*this,t)(v);
    }
    int val;
    State s;
protected:
    std::map<State,car::MemFn> posFunctions;
    void SetVal(int v) {
        val = v;
    }
    void AddVal(int v) {
        val += v;
    }
    void MulVal(int v) {
        val *= v;
    }
};

это работает как я ожидаю. (Я могу вызвать создание автомобильного объекта, присвоить ему определенное состояние и затем вызвать «doit - который будет функцией, вызванной событием» для выполнения действий).

Однако есть одна очень раздражающая вещь: мне нужно создать карту функций (которая отображает состояния с функциями для выполнения) для каждого объекта автомобиля независимо. На самом деле это не так, как «в реальности» (в действительности каждый автомобиль всегда работает одинаково, когда состояние и событие одинаковы) и, следовательно, подвержен ошибкам / ужасен.

Я попытался сделать posFunctions статической картой и использовать статическую функцию инициализации для двух строк в конструкторе.

main.obj: ошибка LNK2001: неразрешенный внешний символ "защищен: статический класс std :: map, класс std :: allocator>> car :: posFunctions" (? PosFunctions @ car @@ 1V? $ Map @ W4State @@ P8car @@ AEXH @ ZU? $ меньше @ W4State @@@ @@ станд В? $ распределитель @ U $ пары? @ $$ CBW4State @@ P8car @@ AEXH @ Z @ станд @@@ 4 @@ станд @@ ) Я предполагаю, что это потому, что я получаю доступ к нестатической функции-члену - даже если она указана?

Возможно ли сделать карту статичной (или глобальной)?

Спасибо за помощь, paul23

Ответы [ 3 ]

3 голосов
/ 19 ноября 2010

Пока вы объявляете map статический, вам необходимо добавить следующую строку в файл реализации:

std::map<State,car::MemFn> car::posFunctions;

Вот ссылка на соответствующий C ++ FAQ item.

2 голосов
/ 19 ноября 2010

Вы забыли определить карту в глобальной области видимости, то есть

std::map<State,car::MemFn> car::posFunctions;

в файле .cpp, где вы определяете автомобиль.когда вы создаете такую ​​конструкцию, спросите себя - не могли бы вы сделать это, используя вместо этого полиморфизм?

1 голос
/ 19 ноября 2010

Это возможно - вы должны определить статическую переменную в 1 месте (файл CPP для этого класса, скорее всего).

std::map<State,car::MemFn> car::posFunctions;

В заголовочном файле у вас есть только объявление .

Это аналогично тому, как вы должны предоставить функцию определение в файле .CPP для каждой функции, которую вы объявляете в заголовке. Если вы пропустите какой-либо из элементов функции, компоновщик выдаст вам ту же ошибку при каждой отсутствующей функции.

Чтобы инициализировать эту структуру по требованию, предоставьте статическую функцию-член, которая вызывается из конструктора вашего класса, но проверяет (потокобезопасным способом, если необходимо), была ли она вызвана ранее.

void car::initFunctions()
{
  static bool done(false);
  if (done)
    return;

  // first pass, set up the map
  done = true;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...