私は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':非静的メンバー関数の不正な呼び出し
私の質問は、submachine
はFSM
のメンバーなので、FSM
のすべての属性のローカルインスタンスにアクセスできないようにする必要がありますか?そうでない場合、FSM
のインスタンスを作成すると、そのすべてのメンバーのインスタンス、つまりsubmachine
が作成されませんか?もしそうなら、なぜ私たちはonentry()
が必要とするオブジェクトを作成する必要があるのでしょうか?
私はコンパイラが正しいと仮定しているので、これを機能させる方法があるかどうかも知りたいです。
注:残念ながら、内部構造体のインスタンス(submachine
)は、イベントが呼び出されたときにインスタンス化されるため、タイプを定義するだけで、FSM
でそれらのオブジェクトをインスタンス化することはできません。
私の質問は、サブマシンはFSMのメンバーであるため、FSMのすべての属性のローカルインスタンスにアクセスできる必要があるということです。
いいえ。Javaとは異なり、内部クラスオブジェクトには外部オブジェクトへの暗黙的な参照がありません。
すべてのメンバー、つまりサブマシンのインスタンスを作成しませんか?
submachine
はtypeであり、メンバー変数ではありません。メンバー変数が必要な場合は、次のようにする必要があります。
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
インスタンスにアクセスできるようにする場合は、インスタンスへの参照を渡す必要があります。
また、参照ではなくポインタを使用できることにも注意してください。実際、多くの場合、ポインターはより高い柔軟性を提供します。
あなたの例では、私は合法的に無料の関数を書くことができると考えてください
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の値を抽出してサブマシンに記録します。
_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()
と言うことができます。
私はあなたがしたいことを推測しているだけですが、私の推測が正しければ、以下のようなことを考えているかもしれません。
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; }
};