Frage

Ich habe eine Klasse CContainer, dass einige Mitglieder CMemberX, CMemberY hat, die voneinander und anderen CClientA unabhängig sind, CClientB Klassen, dass die Verwendung CContainer.

#include "MemberX.h"
#include "MemberY.h"

class CContainer
{
public:
    CMemberX & GetX() const { return m_x; }
    CMemberY & GetY() const { return m_y; }

private:
    CMemberX m_x;
    CMemberY m_y;
};

Ich will, um zu vermeiden alle CClient Klassen neu zu kompilieren, wenn eine der CMember Klassen Vorwärtsdeklarationen und dynamische Zuweisung von m_x und m_y ändern.

Am Anfang habe ich die Mitglieder Zeiger:

// Container.h
class CMemberX;
class CMemberY;

class CContainer
{
public:
    CContainer();
    ~CContainer();

    CMemberX & GetX() const { ASSERT(m_pX != NULL); return *m_pX; }
    CMemberY & GetY() const { ASSERT(m_pY != NULL); return *m_pY; }

private:
    CMemberX* m_pX;
    CMemberY* m_pY;
};

// Container.cpp
#include "Container.h"
#include "MemberX.h"
#include "MemberY.h"

// Allocate members on heap
CContainer::CContainer() : m_pX(new CMemberX()), m_pY(new CMemberY()) {}
CContainer::~CContainer() { delete m_pX; delete m_pY; }

Dann dachte ich, dass ich auch Referenzen anstelle von Zeigern verwenden könnte, so dass es mehr wie der Original-Code aussieht:

// Container.h
class CMemberX;
class CMemberY;

class CContainer
{
public:
    CContainer();
    ~CContainer();

    CMemberX & GetX() const { return m_x; }
    CMemberY & GetY() const { return m_y; }

private:
    CMemberX & m_x;
    CMemberY & m_y;
};

// Container.cpp
#include "Container.h"
#include "MemberX.h"
#include "MemberY.h"

// Allocate members on heap
CContainer::CContainer() : m_x(*new CMemberX()), m_y(*new CMemberY()) {}
CContainer::~CContainer() { delete &m_x; delete &m_y; }

Was ich mag sie nicht über die Zeiger Mitglieder ist, dass es Aussehen wie die Zeiger NULL sein könnten oder die Objekte zur Laufzeit ersetzt werden, was nicht der Fall ist.

Was ich mag nicht über die Referenzen ist, dass der Code in der CTOR und DTor ein bisschen hacky aussieht.

Welcher Ansatz ist vorzuziehen? Gibt es eine bessere Lösung?

Hinweis zum Kopieren / Zuweisen:. Instanzen der CContainer Klasse werden unter keinen Umständen kopiert oder einander zugeordnet werden

War es hilfreich?

Lösung

Ich denke, das ist, was die konstante Variablen sind für:

CMember * const m_x;

Kann nicht m_x ändern nach der Initialisierung ...

Andere Tipps

Ich denke, es ist ein wenig überraschend ist eine Referenz zu verwenden, wenn es Eigentum Semantik ist. Nicht unbedingt macht es eine schlechte Idee, alles in allem, aber es wiegt dagegen.

Ich glaube, ich habe immer nur gebrauchte Referenzen als Mitglieder in Fällen, in denen beide:

  • ein Objekt an den Konstruktor zur Verfügung gestellt, die erforderlich ist, diese Aufgabe zu überdauern.
  • Zuordnung ist verboten, trotzdem.

So zum Beispiel injizierten Abhängigkeiten wie Fabrik oder Dienstobjekte geeignet sein könnte. Gegenüber, dass in C ++ würden Sie bevorzugen oft Abhängigkeiten mit Template-Parameter zu injizieren, anstatt Objekte, so ist vielleicht nicht das Problem auftreten.

Ich finde auch, dass je länger verwende ich C ++, je mehr ich Typen will zuweisbare sein, wenn es ein wirklich guten Grund ist nicht zu sein. Der übliche Trick zur Reduzierung der Kompilierung-Abhängigkeiten in der Art und Weise Sie wollen, ist „Pimpl“, nicht „Rimpl“, aus einem Grund. Durch den Wechsel von einem Objektelement an einem Referenzelement, machen Sie Ihre Klasse nicht-default-kopierbar, wo vorher vielleicht war es kopierbar. Dieses Detail Umsetzung sollte die Klasse des Interface nicht einschränken. Mit Pimpl können Sie sauber Zuordnung und Swap implementieren. Mit diesen Referenzen möchten Sie assign haben oder beide Mitglieder tauschen. Wenn der zweite Swap ausfällt, haben Sie die starke Ausnahme Garantie verloren. Obwohl, wenn Ihr CMemberX und CMemberY Klassen haben keine fail Zuordnung und Swap, das spielt keine Rolle,

Also ich glaube nicht, dass ich wie die Referenz in diesem Fall, aber dann habe ich nicht den Rest des Codes zu sehen. Vielleicht gibt es einen Grund, warum keine der Bedenken hinsichtlich der Zuordnung gelten -. Zum Beispiel, wenn CContainer selbst Klasse eines RAII ist, dann in der Regel die einzigen Lebenszyklus-Operationen soll es ist Aufbau und Zerstörung unterstützt

Es gab eine Menge Fragen hier über die Wünschbarkeit Referenzen als Mitglieder (zum Beispiel: Soll ich liebe Zeiger oder Verweise in den Mitgliedsdaten ), und es scheint mir, dass die Meinung der Mehrheit (der auch meine sein geschieht) ist - nicht. Wenn Sie nicht möchten, dass die Zeiger Make geändert werden, um sie konst. - Ich kann nicht sehen, wie Ihr Code angegeben, sie möglicherweise NULL sein kann

Die dynamische Zuordnung tut nichts für Sie in Bezug auf was Sie wollen. Nicht mit neu kompilieren CClient und CContainer

Die einzige erlaubte Verwendung bei Vorwärtsdeklarationen verwendet, wird erklärt Zeiger (n) mit dem voraus deklarierten Typ.

Sobald Sie eine Methode oder ein Mitglied des voraus deklarierten Typs verwenden wird es nicht kompilieren. Der Compiler muss wissen, die volle Art von was auch immer es ist mit

Kurz gesagt:. Entweder man nie neu kompilieren [Sie sind nur Zeiger auf die Vorwärts deklarierten Typ deklarieren] ODER Sie immer neu kompilieren, falls Sie tatsächlich tun Verwendung CContainer

Steve Jessop bereits die Pimpl Idiom nebenbei erwähnt, aber ich denke, Sie sollten diese aus, wenn Sie nicht bereits über sie gekommen sind: Compilation Firewalls

Im zweiten Codeblock in Ihrer Frage haben Sie privates Mitglied Zeiger, die zusammen mit der übergeordneten Klasse initialisiert und zerstört. Diese Informationen sollen den Leser Ihres Codes genug sein, zu erkennen, was los ist.

Darüber hinaus können Sie die Zeiger const deklarieren: CMember* const m_pX; um anzuzeigen, dass sie nicht nach der Initialisierung geändert werden kann. Nun wird der Compiler versehentliche Änderungen fangen.

Sie kaufen nicht wirklich selbst etwas.
(Ein wenig kürzer Kompilierung in bestimmten Situationen).

Aber Sie sind eine ganze Menge anderen Code gehäuften, dass der Bedarf auf dem Teller gehalten werden.

Wenn diese Objekte sind natürliche Elemente dann als Mitglieder verlassen.
Indem man sich auf dem Stapel zu schaffen und sie als Zeiger oder Referenzen zu speichern, müssen Sie eine ganze Reihe von klebrigen Fragen stellen, dass Bedarf Code, sie zu beantworten.

  • Was passiert, wenn Sie das Objekt kopieren konstruieren.
    • Ich würde normalerweise erwarten, dass die obejct und alle Mitglieder kopiert werden.
      Mit Zeigern oder Referenzen Sie gehen zu müssen, zusätzliche Arbeit tun, um diese Funktionalität zu replizieren, die bereits vorhanden ist.
  • Was passiert, wenn Sie die Objekte zuweisen.
    • Referenzen wird nicht funktionieren (obwohl man dies umgehen, indem Sie Boost-Referenzen).
      Aber Sie immer noch das Problem mit den Mitgliedern erwartet kopiert werden.
  • Was passiert, wenn Sie das Objekt löschen.
    • Wenn Sie implementiert haben alle oben richtig Kopien fein zu machen.
      Andernfalls müssen Sie denken über gemeinsame Zeiger starten um die Funktionalität zu implementieren Sie benötigen.

Wie es steht Versionen 2 und 3 (der Codes in der Frage) sind ernsthaft fehlerhaft und die einzige Version, das funktioniert tatsächlich ist 1.

In meinem Kopf der einfache Tatsache, dass die Wartungskosten so viel niedriger mit 1-Version sein werden, dass entweder die Version 2 oder 3 zu empfehlen kontraproduktiv ist. Die zusätzliche Zeit eine weitere Klasse zu kompilieren, wenn ein Mitglied geändert wird, ist relativ klein im Vergleich zu der Komplexität Sie den Code hinzufügen.

Auch erwähnen Sie in jemand anderes s Kommentar, dass der Code nicht ganz so sauber ist, wie oben beschrieben. Dies unterstreicht nur meinen Punkt, dass diese schlechte Optimierung ist, dass es richtig hart, um die Klasse zu bekommen Arbeit machen und halten sie in diesem Zustand gehalten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top