2009-08-25 8 views
5

C'è un modo per definire riferimenti circolari senza utilizzare i puntatori?Riferimento circolare in C++ senza puntatori

ho bisogno di avere somthing come questo:

struct A; 
struct B { 
    A a; 
}; 

struct A { 
    B b; 
}; 

Grazie!

+1

Nota: Sembra logico per me inoltrare-dichiarare che 'A' è un' class' e successivamente definirlo come 'struct'. – sbi

+0

Quanto sopra non può essere compilato (e non sotto vs2008) perché A non è definito quando viene definita la struttura B. (btw, sì le vostre dichiarazioni future: struct/class dovrebbe corrispondere alle definizioni) – quamrana

risposta

13

È possibile utilizzare i riferimenti al posto

struct A; 
struct B { 
    A& a; 
}; 

struct A { 
    B b; 
}; 

Ma no non è possibile creare un riferimento circolare senza un certo livello di indirezione. Ciò che sta facendo il tuo campione non è nemmeno la creazione di un riferimento circolare, ma sta tentando di creare una definizione ricorsiva. Il risultato sarebbe una struttura di dimensioni infinite e quindi non legale.

+0

Come potrebbe funzionare? Se ricordo bene, il valore dell'indirizzo di un riferimento non può essere modificato una volta impostato, quindi non è possibile definire un riferimento circolare. –

+0

@ John, sinceramente non ne sono sicuro. L'OP ha però chiesto se fosse possibile definirne uno. Questa definizione è legale e compila (VS2008 SP1). – JaredPar

+1

Il costruttore per B prenderebbe un riferimento ad un A e il costruttore per A inizializzerebbe il suo membro B con * this. –

15

No, non c'è. Tale struttura avrebbe dimensioni infinite.

È possibile utilizzare i puntatori intelligenti (shared_ptr e weak_ptr) per evitare la manipolazione diretta del puntatore, ma questo è tutto.

7

Come potrebbe funzionare? Se ricordo bene, il valore dell'indirizzo di un riferimento non può essere modificato una volta impostato, quindi non è possibile definire un riferimento circolare.

Potrebbe funzionare nel modo seguente (identica all'Esempio di Jared inclusa costruttori definito):

struct A; 

struct B { 
    A& m_a; 
    B(A& a) : m_a(a) {} 
}; 

struct A { 
    B m_b; 
    //construct B m_b member using a reference to self 
    A() : m_b(*this) {} 
    //construct B m_b member using a reference to other 
    A(A& other) : m_b(other) {} 
}; 
+0

Vecchio thread, ma ho appena usato la soluzione in una macchina a stati, vedere il commento qui sotto. – kert

1

In C++, T o significa "un oggetto di tipo T, non un riferimento a qualche T (come, per esempio, con i tipi di riferimento in C# e Java). con il codice dalla tua domanda, tipo A avrebbe un oggetto sub di tipo B (chiamato b), e che B a sua volta, avrebbe un oggetto sub di tipo A (nome a). Ora, quello a avrebbe a sua volta un altro A all'interno (di nuovo chiamato a), che poi ha un altro B, che ...

No, questo non funzionerà.

Che probabilmente si desidera è che un Asiano state ottenute ad un B, che a loro volta siano state ottenute che A. Questo può essere fatto usando i puntatori:

struct A; 
struct B { 
    A* a; 
    B(A*); 
}; 

struct A { 
    B* b; 
    A(B* b_) : b(b_) { if(b) b.a = this; } 
}; 

B::B(A* a_) : : a(a_) { if(a) a.b = this; } 

Non penso che si possa fare usando i riferimenti.

0

soluzione ChrisW può essere generalizzato un po 'come questo:

template <class defaultState> struct Context; 

struct State1 { 
    Context<State1>& mContext; 
    State1(Context<State1> & ref) : mContext(ref) {} 
}; 

template <class TDefaultState> 
struct Context { 
    TDefaultState mState; 
    Context() : mState(*this) {} 
}; 

Questo ora permette di fare

Context<State1> demo; 

Inoltre, Stato può avere un po' di codice di supporto template così

template <class State> 
struct TState { 
    typedef Context<State> TContext; 
    typedef TState<State> TBase; 
    Context<State> & mContext; 
    TState(Context<State> &ref) : mContext(ref) {} 
}; 

struct State2 : TState<State2> { 
    State2(TContext & ref) : TBase(ref) {} 
}; 
struct State3 : TState<State3> { 
    State3(TContext & ref) : TBase(ref) {} 
}; 

Che ora ti permette di fare qualsiasi di

Context<State2> demo2; 
Context<State3> demo3;