C ++ classe annidata / problema dichiarazione anticipata
-
25-09-2019 - |
Domanda
E 'possibile inoltrare-dichiarare una classe annidata, quindi utilizzare come tipo di cemento (non puntatore / riferimento a) membro di dati della classe esterna?
cioè.
class Outer;
class Outer::MaybeThisWay // Error: Outer is undefined
{
};
class Outer
{
MaybeThisWay x;
class MaybeThatOtherWay;
MaybeThatOtherWay y; // Error: MaybeThatOtherWay is undefined
};
Soluzione
Non puoi avanti dichiarare una classe annidata del genere.
A seconda di quello che stai cercando di fare, forse è possibile utilizzare uno spazio dei nomi, piuttosto che una classe sullo strato esterno. È possibile inoltrare-dichiarare una tale classe non è un problema:
namespace Outer {
struct Inner;
};
Outer::Inner* sweets; // Outer::Inner is incomplete so
// I can only make a pointer to it
Se il vostro esterno deve assolutamente essere una classe, e non si può calzascarpe in uno spazio dei nomi, quindi avrete bisogno per esterno per essere un tipo completo nel contesto in cui si dichiara avanti interno.
class Outer
{
class Inner; // Inner forward-declared
}; // Outer is fully-defined now
Outer yes; // Outer is complete, you can make instances of it
Outer::Inner* fun; // Inner is incomplete, you can only make
// pointers/references to it
class Outer::Inner
{
}; // now Inner is fully-defined too
Outer::Inner win; // Now I can make instances of Inner too
Altri suggerimenti
Non c'è modo di dichiarare in avanti una classe annidata senza specificare completamente la classe che contiene. Questo piccolo trucco risolve un pò il problema se
class Outer_Inner
{
};
class Outer
{
public:
typedef Outer_Inner Inner;
};
Questo funziona per me, come nel mio Outer_Inner
convenzione di denominazione non è un nome di classe valida, quindi è ovvio che si riferisce a una classe annidata.
non è ancora possibile in avanti dichiarare la classe annidata in questo modo:
class Outer::Inner;
Ma almeno può essere avanti dichiarato con:
class Outer_Inner;
Se non ti piace il modo in cui Outer_Inner aspetto si potrebbe adottare una convenzione di denominazione per le classi nidificate che meglio si adatta ai vostri gusti. Outer__Inner
, Outer_nested_Inner
, ecc.
No, ma cosa c'è di sbagliato con il
class Outer {
public: //or protected or private
class Inner {
};
private:
Inner foo;
};
Inoltra dichiarando non ha senso qui, a meno che mi manca qualcosa (il che è possibile vedere come la tua domanda è carente in un sacco di dettagli)
Ricordate, se una classe è dichiarata in avanti allora si può solo dichiarare riferimenti a o puntatori a un oggetto di tipo forward dichiarato. Non si può fare qualsiasi altra cosa con esso, compreso l'accesso ai suoi membri o funzioni.
Se una classe è stata dichiarata in avanti (ma non hanno ancora la definizione completa) allora si può solo dichiarare un puntatore ad esso, perché il compilatore non sa ancora la dimensione della classe (né i nomi dei suoi campi o metodi).
Se si dichiara un attributo di tipo MaybeThatOtherWay
, non un riferimento né un puntatore, il compilatore deve conoscere la definizione completa della classe per determinare la dimensione della classe esterna. Quindi, non è possibile utilizzare la dichiarazione in avanti e quel tipo di dichiarazione di campo, che si tratti di una classe annidata oppure no.
Se avete solo bisogno di un tipo come parametro di funzione o variabile statica, che potrebbe essere fatto sul lato client. Ad esempio, per ricevere la notifica degli eventi da esterno:
Interfaccia:
class Client {
public:
private:
static void gotIt(int event);
class Helper;
};
Implementazione:
#include <outer.hpp>
class Client::Helper {
public:
static void fromOuter(Outer::Inner const& inner)
{
gotIt(inner.event());
}
};