Frage

C ++ newbie Frage. Bitte überprüfen Ich mache es richtig.

Ich habe eine globale Anwendungsklasse ist es kleine Kinder Laichen und ich brauche die Kinder einige der Anwendungsmöglichkeiten Zugang zu geben. Also habe ich beschlossen, sie zu Kindern durch Verweis übergeben.

Getestet habe ich die Idee, wie unten gezeigt. Es scheint gut zu funktionieren. Ich wollte nur sicherstellen, dass ich nicht etwas Gefährliches tun. da sein könnte Fallstricke ich übersehen?

Dad schafft Kinder und gibt ihnen seine Autoschlüssel:

#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();
}
War es hilfreich?

Lösung

Sieht mir gut (wenn alle Schlüssel ist, dass sie benötigen). Sie könnten einige andere Dienste von Dad müssen, die später angefordert werden - wie:

Wallet += MyDad.GasMoney(REQUEST_MAX_AND_PROMISE_TO_BE_HOME_BY_10PM) ;

Aber sie haben nicht einen Verweis auf Dad, so dass sie nicht in der Lage sein, das zu tun. So würde ich das CChild Konstruktor einen this Bezug nehmen, auch.

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

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

etc.

Und dann CChild Konstruktor müßte ICashProvider und IChaffeur nehmen, wie es CWife und CGirlfriend (und CBoyfriend, vielleicht). An diesem Punkt, ich glaube, Sie könnten erkennen, dass diese Ebene der Granularität im Angesicht der Dad Verantwortlichkeiten sinnlos ist und Sie nur jeder this geben und haben Dad Anfragen zu authentifizieren, indem Anrufer zwingen, ihre eigenen this auf einige Methoden zu senden, so dass Sie nicht Dad Durchführung Inzest oder die CWife Windel haben zu ändern.

Andere Tipps

Passing durch Bezugnahme ist ziemlich das gleiche, die durch Zeiger vorbei mit Ausnahme Semantik und die Tatsache, dass Sie nichts mit dem Zeiger selbst wenn vorbeiReferenz tun können.

Der Code ist in Ordnung.

In Ihrem speziellen Fall, Autoschlüssel sind wahrscheinlich nicht dauerhaft gewährt werden, sondern bei Bedarf angefordert und gewährt auf je Anfrage. Es ist also mehr

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

In mehr genral Fall der Haupt-App-Klasse und Kinder, wie etwa das Datenobjekt von App und Kindern in Haupt geteilt zu schaffen () und thereferences jedem vorbei.

Es ist möglich, und in Ihrem Code verursacht es nicht schaden. Aber es ist gefährlich, denn wenn man CDAD kopieren, dann werden die Schlüssel und Zeiger entlang kopiert werden. Die Objekte, die die Zeiger-zu-Punkt, und die Referenz innerhalb dieser Objekte jedoch werden das gleiche bleiben. Wenn das Original dann CDAD Objekt den Gültigkeitsbereich verlässt, baumeln die Verweise in den Objekten durch die Zeiger verwiesen wird, mehr kein gültiges Objekt verweist.

Vielleicht können Sie Leben umkehren: Erstellen Sie die Tasten auf dem Heap, und die Kinder als normale Mitglieder innerhalb der Klasse. Also, wenn Sie Papa kopieren, werden die Kinder kopiert, aber die Tasten nicht. Ich denke, Schlüssel unveränderlich sind, so können Sie den gleichen Schlüssel auf mehrere Kinder teilen.

Das bringt zu einem anderen Punkt: Wenn Sie Ihre Schlüssel vernünftig klein sind (sprich: nicht sehr groß) und unveränderlich (so haben Sie keine Update-Anomalien, wenn Sie einen Schlüssel zu ändern, aber nicht die andere), hält es die Schaffung nicht auf dem Heap zu - so werden sie automatisch zusammen zu kopiert, und sie an die Kinder weitergeben, wenn sie den Schlüssel benötigen. Sie können sie normale Zeiger der Kinder machen, aber ich denke, das ist hässlich, weil das Kind nicht enthalten ein Schlüssel - aber nutzt. So ein Zeiger / Verweis oder ein Funktionsparameter paßt gut, aber nicht ein „echtes“ Datenelement.

Wenn Sie mit dem Shared-Key werden und die Schlüssel-on-Haufen, sollten Sie intelligente Zeiger verwenden - weil Sie den Überblick über alle Kinder und Väter zu halten haben. Wenn das letzte Kind / Vater den Gültigkeitsbereich verlässt, müssen Sie den Schlüssel wieder gelöscht werden. Sie verwenden boost::shared_ptr dafür:

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

Natürlich können Sie all diese Komplexität vermeiden, indem sie nur machen die CDAD Klasse nicht kopierbar. Dann können Sie Ihre ursprüngliche Lösung verwenden, nur mit der Herstellung die Kinder eine shared_ptr nutzen und die Kinder nicht kopierbar machen. Idealerweise sollte man einen nicht-freigegebenen Zeiger, wie auto_ptr verwenden, aber das auto_ptr hat einige Tücken, die Shared_ptr alle vermeidet:

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

Wenn ich eine solche Klassenhierarchie zu implementieren wäre, hätte ich mit dieser Lösung gehen, oder einfach nur die Schlüssel als Mitglieder fallen, und übergeben / sie schaffen, wenn die Kinder benötigt. Einige andere Hinweise über Ihren Code:

  • Bessere fällt den „_“ von Mitgliedern oder sie am Ende setzen oder eine andere Schreibweise verwenden. Ein Name, der mit einem Unterstrich beginnt und wird von einem Großbuchstaben gefolgt ist reserviert von C ++ Implementierungen (Compiler, C ++ std lib ...).
  • Ich persönlich finde es verwirrend Mitgliedernamen haben und Variablen mit einem Großbuchstaben beginnen. Ich habe es nur sehr selten gesehen. Aber das ist nicht viel zu kümmern, es ist nur über persönlichen Stil.
  • Es gibt eine berühmte Regel ( Null-Eins-Infinity-), die besagt, wenn Sie bekam zwei Dinge von etwas, sollten Sie generell in der Lage sein, beliebig viele Dinge davon zu haben. Also, wenn Sie zwei Kinder haben - warum haben nicht viele von ihnen? Zwei scheint wie eine willkürliche Wahl. Aber es kann einen guten Grund, in Ihrem Fall hat -. So dass diese ignorieren, wenn in Ihrem Fall ist es sinnvoll
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top