Question

J'ai un CContainer de classe qui a des membres CMemberX, CMemberY, qui sont indépendants les uns des autres et d'autres CClientA, des cours de CClientB qui utilisent 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;
};

Je veux éviter d'avoir à recompiler toutes les classes de CClient lors de la modification d'une des classes de CMember en utilisant l'avant et l'allocation dynamique des déclarations de m_x et m_y.

Dans un premier temps, je fait les pointeurs membres:

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

Alors je pensais que je pourrais aussi bien utiliser des références au lieu de pointeurs, il ressemble plus à le code d'origine:

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

Ce que je n'aime pas les membres du pointeur est qu'il ressemble comme les pointeurs pourraient être NULL ou les objets remplacés lors de l'exécution, ce qui est le cas.

Ce que je n'aime pas les références est que le code dans le Ctor et dtor ressemble un peu hacky.

Quelle approche est préférable? Y at-il une meilleure solution?

Remarque concernant la copie / l'attribution:. Les instances de la classe CContainer ne seront en aucun cas être copiés ou assignés à l'autre

Était-ce utile?

La solution

Je pense que ce que les variables sont const pour:

CMember * const m_x;

Impossible de changer m_x après l'initialisation ...

Autres conseils

Je pense qu'il est un peu surprenant d'utiliser une référence quand il y a une sémantique de propriété. Ne pas nécessairement en font une mauvaise idée, tout bien considéré, mais il ne pèse contre.

Je pense que je ne l'ai jamais utilisé des références en tant que membres dans les cas où les deux:

  • un objet est fourni au constructeur, qui est nécessaire pour survivre à cet objet.
  • cession est interdite de toute façon.

Ainsi, par exemple, les dépendances injecté tels que les objets d'usine ou les services peuvent être adaptés. Par contre cela, en C ++ que vous souhaitez souvent préférez injecter des dépendances avec des paramètres de modèle plutôt que des objets, de sorte que la question ne se posera pas peut-être.

Je trouve aussi que plus j'utilise C ++, plus je veux types cessibles moins qu'il y ait une très bonne raison de ne pas être. L'astuce habituelle de réduire les dépendances de compilation de la manière que vous voulez est « Pimpl », pas « Rimpl », pour une raison. En passant d'un membre de l'objet à un élément de référence, vous faites votre classe par défaut non-falsifiable, où, auparavant, peut-être était copiable. Ce détail de mise en œuvre ne doit pas limiter l'interface de la classe. Avec Pimpl vous pouvez mettre en œuvre proprement cession et d'échange. Avec ces références, vous devrez céder ou échanger les deux membres. Si le second swap échoue, vous avez perdu la forte garantie d'exception. Bien que si vos classes CMemberX et CMemberY ont sans échec et cession swap, cela n'a aucune importance

Je ne pense pas que j'aime la référence dans ce cas, mais je ne l'ai pas vu le reste de votre code. Peut-être qu'il ya une raison pour laquelle aucune des préoccupations au sujet de la cession applique -. Par exemple si CContainer lui-même est une classe RAII, alors généralement les seules opérations du cycle de vie, il doit soutenir sont la construction et la destruction

Il y a eu beaucoup de questions ici sur l'opportunité d'utiliser des références en tant que membres (par exemple Si je préfère des pointeurs ou des références dans les données membres ), et il me semble que l'opinion majoritaire (qui se trouve être aussi le mien) est - non. Si vous ne voulez pas les pointeurs à modifier les rendre const -. Je ne vois pas comment, étant donné votre code, ils peuvent éventuellement être NULL

L'allocation dynamique ne fait rien pour vous en ce qui concerne ce que vous voulez. Ne pas avoir à recompiler CClient et CContainer

La seule utilisation autorisée lors de l'utilisation de l'avant des déclarations est pointeur déclarant (s) du type déclaré avant.

Dès que vous utilisez une méthode ou un membre du type avant-déclarée ne compilera pas: le compilateur doit connaître le type complet de ce qu'il utilise

.

En bref: soit vous ne jamais avoir à recompiler [vous ne déclarez des pointeurs du type déclaré de l'avant] ou que vous avez toujours recompiler, au cas où vous avez réellement utiliser CContainer

.

Steve Jessop déjà mentionné l'idiome Pimpl en passant, mais je pense que vous devriez vérifier si vous ne l'avez pas déjà venu à travers elle: Compilation Firewalls

Dans le second bloc de code dans votre question que vous avez des pointeurs membres privés qui sont initialisés et détruits en même temps que la classe parente. Cette information devrait être suffisant pour le lecteur de votre code pour réaliser ce qui se passe.

En outre, vous pouvez déclarer les pointeurs const: CMember* const m_pX; pour indiquer qu'ils ne peuvent pas être modifiés après l'initialisation. Maintenant, le compilateur attraper les modifications accidentelles.

Vous n'êtes pas vraiment vous acheter quoi que ce soit.
(Compilation un peu plus courte dans des situations limitées).

Mais vous amasseras beaucoup d'autre code qui doit être maintenu dans votre assiette.

Si ces objets sont membres naturels les laissent ensuite en tant que membres.
En les créant sur la pile et de les stocker sous forme de pointeurs ou des références que vous devez poser un tas de questions collantes qui ont besoin du code pour y répondre.

  • Qu'est-ce qui se passe lorsque vous copiez construire l'objet.
    • Je me attends normalement obejct et tous ses membres à copier.
      En utilisant des pointeurs ou des références que vous allez devoir faire un travail supplémentaire pour reproduire cette fonctionnalité qui est déjà fourni.
  • Qu'est-ce qui se passe lorsque vous attribuez les objets.
    • Les références ne fonctionnera pas (si vous contourner ce problème en utilisant des références de boost).
      Mais vous avez encore le problème avec attendre les membres à copier.
  • Qu'est-ce qui se passe lorsque vous supprimez l'objet.
    • Si vous avez implémenté correctement tous les ci-dessus pour faire des copies fines.
      Sinon, vous devez commencer à penser à des pointeurs partagés pour mettre en œuvre les fonctionnalités dont vous avez besoin.

En l'état actuel des versions 2 et 3 (du code dans la question) sont gravement viciée et la seule version qui fonctionne réellement est 1.

Dans mon esprit, le simple fait que les coûts d'entretien seront beaucoup plus bas avec la version 1, que la recommandation soit de la version 2 ou 3 est contre-productif. Le temps supplémentaire pour compiler une plus classe quand un membre est modifié est relativement faible par rapport à la complexité que vous ajoutez au code.

vous mentionnez également dans quelqu'un d'autre commentaire s que le code est pas tout à fait aussi propre que celui décrit ci-dessus. Ce juste souligne mon point que cela est mauvais optimisation, il sera difficile d'obtenir fonctionner correctement la classe et le garder maintenu dans cet état.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top