Dépendance circulaire en C++

Les faits:

  • j'ai deux classes prédominantes: gestionnaire et spécialiste.
  • Il y a plusieurs différents types de Spécialistes.
  • <!-Les spécialistes ont souvent besoin de l'aide d'autres spécialistes pour accomplir leur travail.
  • le Gestionnaire connaît tous les spécialistes, et au départ, chaque spécialiste ne connaît que son gestionnaire. (C'est le problème.)
  • à l'exécution, le Gestionnaire crée et stocke une liste de spécialistes. Ensuite, le directeur parcourt la liste et demande à chaque Spécialiste de l'initialiser. Lors de leur initialisation, chaque spécialiste demande au gestionnaire de lui fournir d'autres spécialistes qui remplissent une certaine description. Une fois cette tâche terminée, le Gestionnaire entre dans une boucle au cours de laquelle on demande aux spécialistes d'effectuer leur tâche spécialisée de façon séquentielle.

il me semble que c'est un bon modèle, mais depuis un Manager a une liste de Spécialistes et d'un Spécialiste un Manager, je suis la circulaire de problèmes de dépendance.

c'Est un cas où je devrais en quelque sorte avant de déclarer l'existence d'une classe d'une autre? (Si oui, comment?) Ou devrais-je utiliser un modèle de conception pour résoudre ce problème? (Si oui quoi?) Également... Je pensais que le modèle lui-même était assez O. K. ça ne me dérangerait pas qu'on m'aide à comprendre pourquoi c'est une mauvaise chose.

17
demandé sur JnBrymn 2010-10-26 01:00:43

5 réponses

dans les deux cas, forward déclare l'autre classe:

Gestionnaire.h

class Specialist;

class Manager
{
    std::list<Specialist*> m_specialists;
};

Spécialiste.h

class Manager;

class Specialist
{
    Manager* m_myManager;
};

le seul moment où vous avez besoin d'introduire le fichier d'en-tête pour une classe est quand vous avez besoin d'utiliser une fonction de membre ou une variable dans cette classe, ou besoin d'utiliser la classe comme un type de valeur etc. Quand vous avez seulement besoin d'un pointeur ou d'une référence à une classe, une déclaration suffit.

notez que vers l'avant les déclarations ne sont pas seulement pour résoudre des dépendances circulaires. Dans la mesure du possible, vous devez utiliser les déclarations transmises. Ils sont toujours préférable à l'inclusion d'un fichier d'en-tête supplémentaire s'il est viable.

23
répondu Peter Alexander 2010-10-25 21:17:01

C'est une question de goût, mais avant la déclaration est souvent une bonne alternative aux includes dans les fichiers d'en-tête, même sans dépendance circulaire. (Je n'ai pas envie de relancer une discussion sur qu'à cet endroit. Donc, voici un exemple sur la façon d'appliquer l'avant déclarations pour ton problème:

Dans Manager.h:

// Forward declaration:
class Specialist;

// Class declaration:
class Manager
{
    // Manager declarations go here.
    // Only pointers or references to
    // the Specialist class are used.
};

Dans Manager.rpc:

#include "Specialist.h"

// Manager definitions/implementations
// using the Specialist class go here.
// Full Specialist functionality can be used.

En Spécialiste.h:

// Forward declaration:
class Manager;

// Class declaration:
class Specialist
{
    // Specialist declarations go here.
    // Only pointers or references to
    // the Manager class are used.
};

En Spécialiste.rpc:

#include "Manager.h"

// Specialist definitions/implementations
// using the Manager class go here.
// Full Manager functionality can be used.
9
répondu Flinsch 2010-10-26 05:13:21

Une option est de les déclarer avant l'une des personnes, comme vous le suggérez:

struct specialist;

struct manager
{
    std::vector<std::shared_ptr<specialist> > subordinates_;
};

struct specialist
{
    std::weak_ptr<manager> boss_;
};

cependant, si vous finissez par avoir plus d'une arborescence-structure (où vous avez plusieurs couches de gestion, un

struct person
{
    virtual ~person() { }
    std::weak_ptr<person> boss_;
    std::vector<std::shared_ptr<person> > subordinates_;
};

vous pouvez alors dériver des classes spécifiques pour différents types de personnes dans la hiérarchie. Si vous devez ou non cela dépend exactement comment vous avez l'intention d'utiliser les classes.

si votre implémentation ne supporte pas std::shared_ptr, il peut prendre en charge std::tr1::shared_ptr ou vous pouvez utiliser boost::shared_ptr.

1
répondu James McNellis 2010-10-25 21:03:31

c'est normal des choses. Vous avez juste besoin d'

class Manager;

dans l'en-tête du spécialiste et

class Specialist; 

dans le gestionnaire de l'en-tête

1
répondu pm100 2010-10-25 21:04:22

pendant que tout le monde répond à la question principale, j'ai pensé que je pourrais le souligner.

à l'exécution, le Gestionnaire crée et stocke une liste de spécialistes. Ensuite, le directeur parcourt la liste et demande à chaque Spécialiste de l'initialiser. Lors de leur initialisation, chaque spécialiste demande au gestionnaire de lui fournir d'autres spécialistes qui remplissent une certaine description. Une fois cette étape franchie, le Gestionnaire entre dans une boucle au cours de laquelle les spécialistes sont invités de façon séquentielle pour accomplir leur tâche spécialisée.

je veux juste souligner que ce doit être un processus en deux étapes. Comment le gestionnaire peut-il indiquer au spécialiste 1 Quels sont les spécialistes dont il dispose pour la tâche B si le gestionnaire ne connaît qu'un seul spécialiste à ce jour? Si vous avez besoin de:

1) le gestionnaire passe en revue la liste des spécialistes et leur demande de s'identifier.

2) le gestionnaire passe en revue la liste des spécialistes et leur demande quelles sont les Spécialités auxquelles ils doivent avoir accès, leur disant qui peut répondre à leurs besoins.

3) le gestionnaire va bien la liste des spécialistes et leur dit d'effectuer leurs actions.

1
répondu jmucchiello 2010-10-25 21:29:36