2009-08-25 10 views
5

Czy istnieje sposób definiowania odwołań cyklicznych bez użycia wskaźników?Okólnik w języku C++ bez wskaźników

muszę mieć somthing tak:

struct A; 
struct B { 
    A a; 
}; 

struct A { 
    B b; 
}; 

Dzięki!

+1

Uwaga: Wydaje mi się, żebym był forwardem - deklaruję "A" jako "klasę", a później definiuję ją jako "struct". – sbi

+0

Powyższe nie może kompilować - i nie jest pod vs2008 - ponieważ A nie jest zdefiniowane, gdy definiowana jest struktura B. (btw, tak, twoje deklaracje forward: struct/class powinny pasować do definicji) – quamrana

Odpowiedz

13

Można używać odwołań zamiast

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

struct A { 
    B b; 
}; 

Ale nie to nie jest możliwe, aby utworzyć odwołanie cykliczne bez pewnego poziomu zadnie. Twoja próbka nie tworzy nawet odwołania cyklicznego, ale próbuje utworzyć definicję rekursywną. Rezultatem byłaby struktura o nieskończonej wielkości, a więc nie legalna.

+0

Jak to działa? Jeśli dobrze pamiętam, wartość adresu odniesienia nie może być zmieniana raz ustawiona, więc nie można zdefiniować odwołania kołowego. –

+0

@John, prawdę mówiąc, nie jestem pewien. OP zadał pytanie, czy można go zdefiniować. Ta definicja jest legalna i kompiluje (VS2008 SP1). – JaredPar

+1

Konstruktor dla B odwołałby się do A, a konstruktor dla A zainicjowałby swój element B tym *. –

15

Nie, nie ma. Taka struktura miałaby nieskończoną wielkość.

Możesz używać inteligentnych wskaźników (shared_ptr i weak_ptr), aby uniknąć bezpośredniego manipulowania wskaźnikami, ale to już wszystko.

7

Jak to działa? Jeśli dobrze pamiętam, wartość adresu odniesienia nie może być zmieniana raz ustawiona, więc nie można zdefiniować odwołania kołowego.

To może działać jak następuje (taki sam jak w przykładzie Jareda powiększonej konstruktorów zdefiniowano)

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

Stary wątek, ale użyłem twojego rozwiązania w automatyce stanów, zobacz komentarz poniżej. – kert

1

W C++ T o oznacza „oznacza przedmiot typu T, nie powołując się na pewne T (jak na przykład z typami referencyjnymi w języku C# i Java) Za pomocą kodu z twojego pytania typ A miałby podrzędny obiekt typu B (o nazwie b), a ten z kolei miałby obiekt podrzędny typu A (o nazwie a) Teraz to a ma z kolei inny A w środku (ponownie o nazwie a), który następnie ma inny B, który ...

Nie, to nie zadziała.

Co prawdopodobnie chcesz, jest to, że Areferres do B, co z kolei referres że A. Można to zrobić za pomocą wskaźników:

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

Nie sądzę, że można tego dokonać za pomocą odnośników.

0

rozwiązanie ChrisW można uogólnić trochę tak:

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

To teraz pozwala na wykonywanie

Context<State1> demo; 

dalej, państwo może mieć jakiś szablon kodu pomocnika oraz

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

Który teraz pozwala wykonać dowolne z

Context<State2> demo2; 
Context<State3> demo3; 
Powiązane problemy