web-dev-qa-db-ja.com

外部クラスにアクセスする内部クラス

私はC++に比較的慣れていないので、このことに対する答えをたくさん探しましたが、満足のいく答えは得られませんでした。

FSMという構造があるとします。最終的に私のコードでは、FSMの複数のインスタンスを作成できます。 FSMの属性の1つは、静的ではない_int X_です。FSMのすべてのインスタンスは、Xに独自の値を持つ必要があります。

ここで、FSMの属性の1つは、次のようにsubmachineの値を読み取る必要がある別の構造体Xです。

_struct FSM
{
  public:
    int x;

    int getX(){return x;}

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

これにより、次のエラーが発生します。

エラー: 'FSM :: getX':非静的メンバー関数の不正な呼び出し

私の質問は、submachineFSMのメンバーなので、FSMのすべての属性のローカルインスタンスにアクセスできないようにする必要がありますか?そうでない場合、FSMのインスタンスを作成すると、そのすべてのメンバーのインスタンス、つまりsubmachineが作成されませんか?もしそうなら、なぜ私たちはonentry()が必要とするオブジェクトを作成する必要があるのでしょうか?

私はコンパイラが正しいと仮定しているので、これを機能させる方法があるかどうかも知りたいです。

注:残念ながら、内部構造体のインスタンス(submachine)は、イベントが呼び出されたときにインスタンス化されるため、タイプを定義するだけで、FSMでそれらのオブジェクトをインスタンス化することはできません。

20
Kam

私の質問は、サブマシンはFSMのメンバーであるため、FSMのすべての属性のローカルインスタンスにアクセスできる必要があるということです。

いいえ。Javaとは異なり、内部クラスオブジェクトには外部オブジェクトへの暗黙的な参照がありません。

すべてのメンバー、つまりサブマシンのインスタンスを作成しませんか?

submachinetypeであり、メンバー変数ではありません。メンバー変数が必要な場合は、次のようにする必要があります。

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インスタンスにアクセスできるようにする場合は、インスタンスへの参照を渡す必要があります。

また、参照ではなくポインタを使用できることにも注意してください。実際、多くの場合、ポインターはより高い柔軟性を提供します。

35

あなたの例では、私は合法的に無料の関数を書くことができると考えてください

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

ここで、subが参照できるnoFSMインスタンスがあります。

Oliが言うように、submachineオブジェクトにその親のFSMオブジェクトへの参照を保存させるか、xの値を直接onentryに渡すだけです。 (それがどのように呼び出されるかは明確ではありません)。


Boost.MSM docs をざっと見てみると、このメモは non-default-constructed submachines で見つかりました。

それはかなり醜いです、私はそれをここで言い換えるのに十分なバックエンドを理解していません、そしてリテラルコードは貼り付ける価値があるように分離して十分に意味をなさないでしょう。

そこからリンクされているサンプルコードは、次のシグネチャを持つサブマシンのentryメソッドも示しています。

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

それが正確であれば、外部状態マシンへのポインタを保存することもできますon_entry、またはそこでxの値を抽出してサブマシンに記録します。

3
Useless

_struct submachine_の宣言はtypeのみを定義することに注意してください。そのタイプのクラスに実際にフィールドを作成するわけではありません。

次のいずれかが必要です。

_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) {}のようなコンストラクターなど)を含めて、初期化する必要があります。特定のX値にアクセスするには、fsm_->getX()と言うことができます。

2
Kevin Grant

私はあなたがしたいことを推測しているだけですが、私の推測が正しければ、以下のようなことを考えているかもしれません。

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; }
};
1
jxh