22

我对 C++ 比较陌生,我已经为这件事寻找了很多答案,但我从来没有得到令人满意的答案。

假设我有一个名为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,我们不会创建其所有成员的实例,即 iesubmachine吗?如果是这样,那我们为什么需要创建一个需要的对象onentry()呢?

我假设编译器是正确的,所以我也想知道是否有办法让它工作。

注意:不幸的是,内部结构 ( submachine) 的实例在调用事件时被实例化,因此我只能定义类型,而不能在FSM.

4

4 回答 4

40

我的问题是,submachine 是 FSM 的成员,所以它应该可以访问 FSM 的所有属性的本地实例,不是吗?

不。与 Java 不同,内部类对象没有对外部对象的隐式引用。

我们不会创建所有成员的实例,即 submachine 吗?

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实例,则需要传递对实例的引用。

另请注意,您可以使用指针而不是引用。事实上,指针在许多情况下提供了更大的灵活性。

于 2012-07-10T00:29:37.677 回答
3

考虑到在你的例子中,我可以合法地编写一个自由函数

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

没有可以引用的FSM实例。sub

正如 Oli 所说,要么让submachine对象存储对其父FSM对象的引用,要么直接将值传递xonentry(目前尚不清楚它是如何被调用的)。


通过快速浏览Boost.MSM 文档,我发现了这个关于non-default-constructed submachines 的注释。

这很丑陋,我对后端的理解不够,无法在这里解释它,而且文字代码孤立起来也没有足够的意义,值得粘贴。

从那里链接的示例代码还显示了具有以下签名的子机的进入方法:

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

如果这是准确的,您可以存储指向外部状态机的指针on_entry,或者在那里提取 x 的值并将其记录在子机中。

于 2012-07-10T00:56:31.807 回答
2

请注意,声明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值。

于 2012-07-10T00:31:13.580 回答
1

我只是在猜测你想做什么,但如果我的猜测是正确的,你可能会想到类似下面的东西。

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; }
};
于 2012-07-10T00:50:36.597 回答