2012-07-10 116 views
18

我对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();}; 
    }; 
}; 

这提供了以下错误:

Error: 'FSM::getX' : illegal call of non-static member function

我的问题是,submachineFSM的成员,所以不应该有权访问FSM所有属性的本地实例?如果不是,当我们创建FSM的实例时,我们是不是要创建其所有成员的实例,即submachine?如果是这样,那么为什么我们需要创建一个对象onentry()需要?

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

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

回答

34

my question is, submachine is a member of FSM, so it should have access to local instances of all the attributes of FSM, no?

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

wouldn't we be creating an intance of all its members i.e. 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实例,则需要将引用传递给一个实例。

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

+0

如果有一种方法可以完成我想完成的任务吗? – Kam 2012-07-10 00:30:48

+2

Downvoter:关心分享? – 2012-07-10 00:33:51

+0

(对不起,延期,找到链接)。嵌套类是成员,可以像任何其他成员一样访问外部类,请参阅[DR 45](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45),它是自2003年以来的标准 – 2012-07-10 00:35:54

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值。

+0

不幸的是,内部结构的实例被声明为运行时(事件),因此我只能定义类型,而不能为它们创建实例化对象。 – Kam 2012-07-10 00:32:38

+2

你仍然不能'int g = getX();'没有'FSM'对象。这是如何回答这个问题的? – 2012-07-10 00:35:09

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; } 
}; 
3

认为在你的榜样,我可以合法地写一个免费功能

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

那里是没有 FSM实例sub可以参考。

无论是作为奥利说,有submachine对象存储的引用其父FSM对象,或者只是经过的x值直接进入onentry(目前还不清楚它如何被调用的)。


从快速浏览一下Boost.MSM docs我发现non-default-constructed submachines此说明。

这是非常丑陋的,我不明白后端足以在这里解释它,并且字面代码不会有足够的意义孤立地值得粘贴。

从那里也与该示例代码显示了冲锋枪的具有以下签名进入方法:

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

如果这是正确的,你可以存储指向你的外在状态机on_entry,或提取的价值在那里,并记录在冲锋枪。

+0

谢谢!这就是我一直在寻找的东西,现在我明白了。这篇文章与OLI的帖子一起为我做了。我希望我能接受这两个答案。 – Kam 2012-07-10 01:10:48