Подтвердить что ты не робот

Внутренний класс, доступ к внешнему классу

Я относительно новичок в С++, и я много искал ответа для этой вещи, но у меня не было удовлетворительного ответа.

Скажем, у меня есть структура, называемая FSM. В конечном итоге в моем коде можно создать несколько экземпляров FSM. Одним из атрибутов FSM является int X, который не является статическим, каждый экземпляр FSM должен иметь собственное значение для X.

Теперь одним из атрибутов FSM является другая структура submachine, которая должна читать значение X следующим образом:

struct FSM
{
  public:
    int x;

    int getX(){return x;}

    struct submachine
    {
        void onentry() {int g = getX();};
    };
};

Это приводит к следующей ошибке:

Ошибка: "FSM:: getX": незаконный вызов нестатической функции-члена

Мой вопрос: submachine является членом FSM, поэтому не должен ли он иметь доступ к локальным экземплярам всех атрибутов FSM? А если нет, когда мы создадим экземпляр FSM, не будем ли мы создавать экземпляр всех его членов, т.е. submachine? И если да, то почему нам нужно создать объект, который нужен onentry()?

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

ПРИМЕЧАНИЕ. К сожалению, экземпляры внутренних структур (submachine) создаются при вызове события и поэтому я могу определить тип, а не создавать объекты для них в FSM.

4b9b3361

Ответ 1

Мой вопрос: автомат является членом FSM, поэтому он должен иметь доступ к локальным экземплярам всех атрибутов FSM, no?

Нет. В отличие от Java, внутренние объекты класса не имеют неявной ссылки на внешний объект.

не будем ли мы создавать интонацию всех его членов, то есть автомата?

submachine - это тип, а не переменная-член. Если вам нужна переменная-член, вам нужно сделать что-то вроде этого:

struct FSM {
    struct submachine {
        ...
    };

    submachine sm;  // Member variable of type submchine
};

И если вы хотите, чтобы sm "видел" его родительский объект, вам нужно передать его явно:

struct FSM {
    struct submachine {
        FSM &parent;  // Reference to parent
        submachine(FSM &f) : parent(f) {}  // Initialise reference in constructor
    };

    submachine sm;

    FSM() : sm(*this) {}  // Pass reference to ourself when initialising sm
};

Обратите внимание, что тот же принцип применяется для экземпляров submachine, которые не являются переменными-членами. Если вы хотите, чтобы у них был доступ к экземпляру FSM, вам нужно передать ссылку на него.

Обратите внимание, что вы можете использовать указатель вместо ссылки. Фактически, во многих случаях указатель обеспечивает большую гибкость.

Ответ 2

считают, что в вашем примере я могу законно написать бесплатную функцию

void foo()
{
    FSM::submachine sub;
    sub.onentry();
}

где нет экземпляра FSM, к которому может обращаться sub.

Либо, как говорит Оли, объект submachine хранит ссылку на свой родительский объект FSM или может просто передать значение x непосредственно в onentry (неясно, как это получается вызывается).


С быстрым просмотром Boost.MSM docs я нашел эту заметку на нестандартные автоматы.

Это довольно уродливо, я не понимаю, что такое backend достаточно, чтобы перефразировать его здесь, и буквальный код не будет иметь достаточного смысла в изоляции, чтобы его можно было вставлять.

Приведенный здесь примерный код также показывает способ ввода в автомат со следующей сигнатурой:

template <class Event,class FSM> void on_entry(Event const&,FSM& );

если это точно, вы можете либо сохранить указатель на свой внешний конечный автомат on_entry, либо извлечь значение x там и записать его в автомат.

Ответ 3

Обратите внимание, что объявление struct submachine определяет только тип; он фактически не создает поле в классе этого типа.

Вам понадобится одно из следующих действий:

struct submachine mysub; // creates a field after the class is defined

или

struct submachine
{
  . . .
} mysub; // creates the field "mysub" also, as the structure is being defined

Это делает поле mysub, и вы получаете доступ к нему так же, как к x.

В определении submachine должно быть указано конкретное FSM (например, поле указателя FSM* и, возможно, конструктор типа submachine(FSM* fsm): fsm_(fsm) {} для его инициализации), чтобы вы могли сказать fsm_->getX() для доступа к определенному x значение.

Ответ 4

Я только догадываюсь о том, что вы хотите сделать, но если мое предположение верно, вы можете подумать о чем-то вроде ниже.

struct FSM_Base {
    int x;

    struct submachine1;
    struct submachine2;

    FSM_Base () : x(0) {}
    virtual ~FSM_Base () {}
};

struct FSM_Base::submachine1 : virtual public FSM_Base {
    void oneentry () { int g = x; }
};

struct FSM_Base::submachine2 : virtual public FSM_Base {
    void oneentry () { int g = x; }
};

struct FSM : public FSM_Base::submachine1,
             public FSM_Base::submachine2 {
    FSM_Base::submachine1 * sub1 () { return this; }
    FSM_Base::submachine2 * sub2 () { return this; }
};