2012-07-10 15 views
18

Jestem względnie nowa w C++ i bardzo długo szukałem odpowiedzi na tę rzecz, ale nigdy nie otrzymałem satysfakcjonującej odpowiedzi.Klasa wewnętrzna uzyskująca dostęp do klasy zewnętrznej

Załóżmy, że mam strukturę o nazwie FSM. W końcu w moim kodzie można utworzyć wiele instancji FSM. Jednym z atrybutów FSM jest int X, który nie jest statyczny, każde wystąpienie FSM powinno mieć własną wartość dla X.

Teraz, jeden z atrybutów FSM „s jest inna struktura submachine który musi odczytać wartość X takiego:

struct FSM 
{ 
    public: 
    int x; 

    int getX(){return x;} 

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

To daje następujący błąd:

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

Moje pytanie brzmi: , submachine jest członkiem FSM, więc czy nie powinien mieć dostępu do lokalnych instancji wszystkich atrybutów FSM? A jeśli nie, kiedy stworzymy instancję FSM, czy nie będziemy tworzyć instancji wszystkich jej członków, tj. submachine? A jeśli tak, to dlaczego potrzebujemy stworzyć obiekt, którego potrzebuje onentry()?

Przyjmuję, że kompilator jest poprawny, więc chciałbym również wiedzieć, czy istnieje sposób, aby to działało.

UWAGA: Niestety instancje wewnętrznych struktur (submachine) są tworzone, gdy wywoływane jest zdarzenie, dlatego mogę tylko zdefiniować typ i nie tworzyć obiektów dla nich w FSM.

Odpowiedz

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?

Nie. W przeciwieństwie do Javy obiekty klasy wewnętrznej nie mają niejawnego odniesienia do zewnętrznego obiektu.

wouldn't we be creating an intance of all its members i.e. submachine?

submachine jest typ, a nie zmienna członkiem. Jeśli chciałeś zmienną składową, trzeba by zrobić coś takiego:

struct FSM { 
    struct submachine { 
     ... 
    }; 

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

A jeśli chcesz sm „zobaczyć” jego obiektu nadrzędnego, trzeba przekazać go wyraźnie:

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

Należy zauważyć, że ta sama zasada dotyczy instancji submachine, które nie są zmiennymi składowymi. Jeśli chcesz, aby mogli uzyskać dostęp do instancji FSM, musisz przekazać odwołanie do jednego.

Należy również pamiętać, że można użyć wskaźnika zamiast odniesienia. W rzeczywistości wskaźnik zapewnia większą elastyczność w wielu przypadkach.

+0

czy jest sposób, w jaki osiągam to, co chcę osiągnąć? – Kam

+2

Downvoter: czy chcesz się podzielić? –

+0

(Przepraszamy za opóźnienie, znajdowaliśmy link). Zagnieżdżone klasy są członkami i mogą uzyskać dostęp do zewnętrznej klasy, tak jak każdy inny członek, patrz [DR 45] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45), część standard od 2003 roku –

2

Należy pamiętać, że zadeklarowanie struct submachine definiuje tylko typ typu; w rzeczywistości nie tworzy pola w klasie tego typu.

Trzeba będzie jedną z następujących czynności:

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

lub

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

To sprawia mysub pole, a następnie dostęp do niego w ten sam sposób, że chcesz uzyskać dostęp x.

Definicja submachine musi zawierać specjalny FSM (na przykład pole wskaźnika FSM* i prawdopodobnie konstruktora jak submachine(FSM* fsm): fsm_(fsm) {} aby go zainicjować), aby można było powiedzieć fsm_->getX() dostęp do pewnej wartości X.

+0

Niestety, wystąpienia wewnętrznych struktur są deklarowane jako czasy działania (zdarzenia), a zatem Mogę tylko zdefiniować typ, a nie wprowadzać do niego obiekty. – Kam

+2

Nadal nie można wykonać 'int g = getX();' bez obiektu 'FSM'. Jak to odpowiada na pytanie? –

1

Zgaduję tylko, co chcesz zrobić, ale jeśli moje przypuszczenie jest poprawne, możesz pomyśleć o czymś podobnym do poniższego.

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

pod uwagę, że w przykładzie, mogę napisać prawnie bezpłatną funkcję

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

gdzie istnieje nie instancja FSM że sub może odnosić się do.

Albo, jak mówi Oli, miał sklep submachine obiektu odniesienie do jego rodzic FSM obiektu, a może po prostu przekazać wartość x bezpośrednio do onentry (nie jest jasne, w jaki sposób zostanie wywołany).


Z szybkim spojrzeniu na Boost.MSM docs znalazłem tę notatkę na non-default-constructed submachines.

To dość brzydkie, nie rozumiem, że backend wystarczy sparafrazować tutaj, a literalny kod nie będzie miał wystarczającego sensu w izolacji, aby być wartym wklejania.

Przykładowy kod związany stamtąd również pokazuje metody wprowadzania podzespołu jest z następującym podpisem:

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

jeśli to dokładne, można przechowywać wskaźnik do zewnętrznej machiny państwowej on_entry lub wyodrębnić wartość x tam i zapisz go w maszynie.

+0

Dziękujemy! Tego właśnie szukałem, teraz tak naprawdę to rozumiem. ten post z postem OLI zrobił to za mnie. Chciałbym móc przyjąć obie odpowiedzi. – Kam

Powiązane problemy