Domanda

C++ newbie domanda.Si prega di verificare la sto facendo è giusto.

Ho una classe di applicazione globale di deposizione delle uova è un po ' bambini e ho bisogno di dare ai bambini l'accesso a determinate applicazioni di strutture.Così ho deciso di passare a bambini da riferimento.

Ho testato l'idea, come mostrato di seguito.E sembra funzionare bene.Ho solo voluto assicurarsi che non sto facendo qualcosa di pericoloso.Potrebbe esserci in qualsiasi insidie che ho trascurato?

Papà crea e dà loro le chiavi della macchina:

#include <iostream>
using namespace std;

class CCarKeys
{
    public:
        CCarKeys(const string& Name) : _Name(Name) {}
        string _Name;
};

class CChild
{
    public:
        CChild(CCarKeys& CarKeys) : _Name("Child"), _CarKeys(CarKeys) {}
        string _Name;
        CCarKeys& _CarKeys;
        void TestHasKeys() {cout << "I got " << _CarKeys._Name << endl;}
};

class CDad
{
    public:
        CDad() : _Name("Dad"), _HondaCarKeys("Honda keys"), _ChevyCarKeys("Chevy keys") {}
        string _Name;
        CCarKeys _HondaCarKeys;
        CCarKeys _ChevyCarKeys;
        CChild *_Boy;
        CChild *_Girl;
        void MakeBoy() {_Boy= new CChild(_HondaCarKeys);}
        void MakeGirl() {_Girl= new CChild(_ChevyCarKeys);}
};

int main ()
{
    CDad Dad;

    Dad.MakeBoy();
    Dad.MakeGirl();
    Dad._Boy->TestHasKeys();
    Dad._Girl->TestHasKeys();
}
È stato utile?

Soluzione

Sembra buono per me (se i tasti è più che sufficiente).Potrebbero aver bisogno di alcuni altri servizi da parte di Papà che sono richieste in un secondo momento - come:

Wallet += MyDad.GasMoney(REQUEST_MAX_AND_PROMISE_TO_BE_HOME_BY_10PM) ;

Ma non hanno un riferimento al Padre, in modo da non essere in grado di farlo.Così avrei la CChild costruttore di prendere un this di riferimento, troppo.

class ICashProvider {
public:
  virtual money Request(IPerson,CashRequestFlags) ;
};

class IChaffeur {
public:
  virtual void Drive(IPerson[]) ;
};

ecc.

E poi CChild costruttore avrebbe bisogno di prendere ICashProvider e IChaffeur, come vorresti CWife e CGirlfriend (e CBoyfriend, forse).A questo punto, penso che si potrebbe rendersi conto che questo livello di dettaglio è inutile a fronte di Dad's le responsabilità e basta dare a tutti this e hanno Dad autenticare le richieste costringendo i chiamanti di inviare la propria this su alcuni metodi, in modo che non hai Dad esecuzione di un incesto o di modifica del CWife's pannolino.

Altri suggerimenti

Il passaggio per riferimento è quasi lo stesso che passa il puntatore tranne che per la semantica e il fatto che non si può fare nulla con il puntatore stesso se il passaggio per riferimento.

Il codice è OK.

Nel tuo caso particolare, le chiavi della macchina non sono suscettibili di essere concesso in modo permanente, ma piuttosto richiesto come necessario e concesso in base a specifiche richieste.Quindi è più

class Dad
{
   /** may return NULL if no keys granted */
   CarKeys *requestKeys(CChild forChild);
}

In più generali caso di applicazione principale di classe e i bambini, come sulla creazione di dati oggetto condiviso da app e bambini in main(), e passando thereferences a tutti.

È possibile e nel codice non causano danni.Ma è pericoloso, perché se si copia CDad, quindi i tasti e i puntatori verranno copiati.Gli oggetti che i puntatori punto di, e il riferimento all'interno di tali oggetti, tuttavia, rimarrà lo stesso.Se l'originale CDad oggetto, quindi, va al di fuori del campo di applicazione, i riferimenti oggetti a cui fanno riferimento i puntatori sono a penzoloni, il riferimento non valido oggetto di più.

Forse si può invertire la durata della vita:Creare le chiavi nel mucchio, e i bambini come normale membri all'interno della classe.Quindi, se si copia il papà, i bambini vengono copiati, ma le chiavi non sono.Penso che i tasti non sono modificabili, quindi è possibile condividere la stessa chiave tra più bambini.

Questo porta ad un altro punto:Se le chiavi sono ragionevoli i piccoli (leggi:non enorme) e immutabile (così non devi aggiornare anomalie se si modifica una chiave, ma non gli altri), considerare la creazione di esso non nel mucchio anche - in modo che essi vengono automaticamente copiati anche troppo, e farli passare per i bambini, quando hanno bisogno della chiave.È possibile rendere il loro normale puntatori dei bambini, ma penso che sia brutto, perché il ragazzo non contenere di un tasto, ma la utilizza.Così un puntatore/o di riferimento di un parametro di funzione, si adatta bene, ma non di un "vero" membro di dati.

Se si sta andando con la chiave condivisa e le chiavi-in-heap, si dovrebbe utilizzare i puntatori intelligenti - perché è necessario tenere traccia di tutti i bambini e i papà.Se l'ultimo bambino/papà va al di fuori del campo di applicazione, è necessario eliminare di nuovo il tasto.Si utilizza boost::shared_ptr per che:

class CCarKeys
{
    public:
        CCarKeys(const string& Name) : _Name(Name) {}
        string _Name;
};

class CChild
{
    public:
        CChild(boost::shared_ptr<CCarKeys> const& CarKeys) 
            : _Name("Child"), _CarKeys(CarKeys) {}
        string _Name;
        boost::shared_ptr<CCarKeys> _CarKeys;
        void TestHasKeys() {cout << "I got " << _CarKeys._Name << endl;}
};

class CDad
{
    public:
        // NOTE: null the kid pointers *if* you use raw pointers, so you can check whether
        // a boy or girl is present. Without nulling them explicitly, they have 
        // indeterminate values. Beware. shared_ptr's however will automatically
        // initialized to default "null" values
        CDad() : 
            _Name("Dad"), 
            _HondaCarKeys(new CCarKeys("Honda keys")), 
            _ChevyCarKeys(new CCarKeys("Chevy keys")) {}
        string _Name;

        boost::shared_ptr<CCarKeys> _HondaCarKeys;
        boost::shared_ptr<CCarKeys> _ChevyCarKeys;

        // also use shared_ptr for the kids. try to avoid raw pointers. 
        boost::shared_ptr<CChild> _Boy;
        boost::shared_otr<CChild> _Girl;

        void MakeBoy() {_Boy.reset(new CChild(_HondaCarKeys));}
        void MakeGirl() {_Girl.reset(new CChild(_ChevyCarKeys));}
};

// main can be used unchanged

Naturalmente, è possibile evitare tutta questa complessità, semplicemente facendo la CDad classe non copiabile.È possibile utilizzare la soluzione originale, solo con i bambini usare un shared_ptr e rendere i bambini non copiabile troppo.Idealmente, si dovrebbe utilizzare un non condiviso puntatore, ad esempio auto_ptr, ma che auto_ptr ha alcuni problemi, che shared_ptr tutte evita:

class CCarKeys
{
    public:
        CCarKeys(const string& Name) : _Name(Name) {}
        string _Name;
};

class CChild
{
    public:
        CChild (CCarKeys& CarKeys) 
            : _Name("Child"), _CarKeys(CarKeys) {}
        string _Name;
        CCarKeys &_CarKeys;
        void TestHasKeys() {cout << "I got " << _CarKeys._Name << endl;}
    private:
        CChild(CChild const&); // non-copyable
        CChild & operator=(CChild const&); // non-assignable
};

class CDad
{
    public:
        CDad() : 
            _Name("Dad"), 
            _HondaCarKeys("Honda keys"), 
            _ChevyCarKeys("Chevy keys") {}
        string _Name;

        CCarKeys _HondaCarKeys;
        CCarKeys _ChevyCarKeys;

        // also use shared_ptr for the kids. try to avoid raw pointers. 
        boost::shared_ptr<CChild> _Boy;
        boost::shared_otr<CChild> _Girl;

        void MakeBoy() {_Boy.reset(new CChild(_HondaCarKeys));}
        void MakeGirl() {_Girl.reset(new CChild(_ChevyCarKeys));}
private:
    CDad(CDad const&); // non-copyable
    CDad & operator=(CDad const&); // non-assignable
};

Se ho dovuto implementare una gerarchia di classi, vorrei andare con la soluzione, o semplicemente cadere le chiavi come membri, e pass/crea quando è necessario per i bambini.Alcune altre note del tuo codice:

  • Meglio cadere il"_", da parte di membri o di metterli alla fine, o usare qualche altra notazione.Un nome che inizia con un carattere di sottolineatura ed è seguito da una lettera maiuscola, è riservato al C++ implementazioni (compilatore C++ std lib ...).
  • Io personalmente trovo confusione con i nomi dei membri e le variabili iniziano con una lettera Maiuscola.L'ho visto molto raramente.Ma questo non è molto a preoccuparsi, si tratta solo di uno stile personale.
  • C'è una famosa regola (Zero-Uno-Infinito) che, uniti, quando le due cose a voi di qualcosa, in genere si dovrebbe essere in grado di avere arbitrario molte cose.Quindi, se si possono avere due figli - perché non hanno molti di loro?Due mi sembra una scelta arbitraria.Ma si può avere una buona ragione nel tuo caso - in modo da ignorare questo quando nel tuo caso ha senso.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top