2015-11-12 14 views
6

ho questo (semplificato) Situazione:risoluzioni di portata più brevi per le classi nidificate privati ​​

class Tree { 
    class Iterator { 
     class Stack { 
      // ... 
     } 
    public: 
     // ... 
    } 
public: 
    //... 
} 

Non voglio ingombrare le definizioni delle classi e decido di scrivere solo dichiarazioni di metodo all'interno delle classi stesse. Più tardi (mooolto basso) quando voglio definire, ad esempio, copiare operatore di assegnamento in questo modo:

Tree::Iterator::Stack& Tree::Iterator::Stack::operator = (const Stack& p_stack) { 
// ... 
} 

ho a che fare con queste risoluzioni portata brutte. Mi chiedo se c'è un modo per accorciarli, perché using e typedef, come li conosco, non mi offrono nulla.

EDIT: Dal momento che questo non è CodeReview, e @Yulian chiesto chiarimenti, ecco la versione corta:

sto facendo un'implementazione iterativa Red-Black Tree. Menzionato class Iterator è per il movimento di post-ordine (quindi è specifico per il post-ordine) e class Stack è la sua classe di utilità. In questo programma breve, solo class Tree utilizza Iterator e solo Iterator utilizza Stack.

Dopo il promemoria di @ Yulian, ho ricordato che sarebbe stato più orientato agli oggetti se le classi menzionate fossero definite separatamente (forse anche come modelli), ma questo è un programma piccolo e autonomo e sto cercando di mantenere in quel modo

EDIT: autonomo significa anche che si tratta di un caso isolato di programma, file singolo, quindi nessun file .h o codice esterno riutilizzo di sorta. Perché? Perché ACADEMIA (e restrizioni arbitrarie associate).

+0

Perché non usare '' e 'typedef' ti compri qualcosa? – lcs

+0

Sono classi private, quindi non posso semplicemente dire 'usando Stack = Tree :: Iterator :: Stack;' o qualcosa di simile - 'Iterator' e' Stack' sono inaccessibili. –

+0

È possibile dichiarare la classe nidificata e quindi definire le funzioni membro in linea, quando si definisce la classe in un secondo momento. Ma penso che il codice sia a posto. Se si dispone anche di una serie di spazi dei nomi per gestire _inside_ le definizioni di funzione, si possono effettivamente inserire dichiarazioni 'using' all'interno di ciascuna definizione di funzione. – SirGuy

risposta

3

È possibile eliminare completamente le risoluzioni degli ambiti con un using o typedef. Ma non con il modo tradizionale perché le tue classi annidate sono dichiarate private. Dovresti quindi utilizzare using nella sezione public di ogni classe annidata per "esporli". Purtroppo, questo rompe il "privatezza" di loro:

class Tree { 
    class Iterator { 
     class Stack { 
      Stack& operator = (const Stack& p_stack); 
     }; 
    public: 
     using Stack_Out = Stack; 

     // ... 
    }; 
public: 
    using Iterator_Out = Iterator::Stack_Out; 
    //... 

}; 

using Stack = Tree::Iterator_Out; 

Stack& Stack::operator = (const Stack& p_stack) { 
// ... 
} 

LIVE DEMO

Si potrebbe tuttavia, rimuovere i livelli di ambito (ad eccezione di quello esterno, vale a dire, Tree::) con fuori esponendo le classi nidificate privati nel seguente modo:

class Tree { 
    class Iterator { 
     friend class Tree; 
     ^^^^^^^^^^^^^^^^^^ 
     class Stack { 
      Stack operator = (const Stack& p_stack); 
     }; 
    public: 

     // ... 
    }; 

    using Stack = Iterator::Stack; 
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

public: 

}; 

Tree::Stack Tree::Stack::operator = (const Stack& p_stack) { 
^^^^^^^^^^^ ^^^^^^^^^^^ 
} 

LIVE DEMO

+0

Le classi annidate sono private solo se dichiarate in una sezione privata. – Deduplicator

+1

Questo non pregiudica l'intero punto di avere le classi private in primo luogo? – SirGuy

+0

@Duplicatore nell'OP sono definiti nella sezione privata. – 101010

0

Prima di tutto è bene spiegare cosa vorresti ottenere e come pensi che questo metodo sia adatto al tuo compito. IMHO, un approccio migliore è quello di creare classi individuali che non siano nidificate e usarle all'interno della classe Tre. Questo approccio è chiamato "HA UN". È più semplice da mantenere e da capire dagli altri. Se fornisci maggiori dettagli, possiamo proporre un design di classe migliore.

+0

Grazie, ho chiarito il contesto ora. –

-2

Puoi lasciare che il preprocessore ti aiuti:

#define foobar Tree::Iterator::Stack  
foobar& foobar::operator = (const Stack& p_stack) { 
    // ... 
} 
+0

Come sono stato criticato [qui] (http://codereview.stackexchange.com/questions/110461/memory-management-for-red-black-tree), le definizioni del preprocessore perfezionano il mondo quando vengono utilizzate inutilmente. –

+2

assolutamente non farlo mai. –