J'ai codé une méthode de croisement d'un algorithme génétique (voir https: // fr .wikipedia.org / wiki / crossover_ (génétique_algorithm) ).
La méthode de crossover modifie les membres privés de la classe de chromosome, mais je l'ai sorti du chromosome dans une classe de base virtuelle séparée Crossovergrate (ami de chromosome ) Pour garder chaque méthode de crossover bien encapsulée dans une sous-classe, c'est-à-dire le modèle de stratégie GOF (voir https: // fr .wikipedia.org / wiki / Stratégie_pattern ). P>
Le problème est que le problème est que les sous-classes de croisement ne peuvent pas accéder aux membres privés de chromosome, car l'amitié n'est pas héritée en C ++. Les 2 seules solutions que je vois sont les suivantes: p>
1) Ajouter des méthodes d'accesseur à la classe de base virtuelle pure par exemple. CrossoverStrategy :: getgenes () pour rendre les membres privés de chromosome accessibles aux sous-classes. Parce que CrossOverStrategy ne peut pas anticiper tout ce que ses sous-classes peuvent vouloir faire du chromosome, je dois l'exposer à l'avant. Ugly! P>
2) Transférer déclarer chaque sous-classe de crosssovergrie et en fait explicitement un ami de chromosome. Cela se sent légèrement moins laid, au moins conserve les interfaces et le nettoyant de code. Je me penche vers cette option pour l'esthétique. P>
Toutes meilleures suggestions de conception? Code ci-dessous. P>
3 Réponses :
L'option 2 doit être rejetée car elle n'a pas échoué. Vous allez continuellement modifier L'option 1 est une idée étrange car elle place la fonction getter pour chromosome code> pour le garder à jour avec le nouveau
CrossOverStrategies code>.
chromosome code> Membres de données de l'extérieur de
chromosome code>. Je peux voir des cas où il s'agit d'une idée attrayante, si
getgenes code> est créé, mais je ne suis pas convaincu ici. Considérez plutôt P>
Option 1-A H1>
#include "Chromosome.h"
#include "CrossoverStrategies.h" // A bad idea. Forces recompilation when strategies are added
int main()
{
Chromosome * p1 = ChromosomeFactory(/* some construction parameters here */);
p1->m_genes.push_back(0.0); // will fail to compile (incomplete type)
Chromosome * p2 = ChromosomeFactory(/* some construction parameters here */);
// probably should hide the next line with a factory as well
CrossoverStrategy * strategy = new CrossoverStrategyExample1();
strategy->crossover(p1, p2);
}
Merci pour les suggestions. Je suis au courant du fait que j'aurais besoin de modifier continuellement Chromosome.h lorsque j'ajoute une nouvelle stratégie. Mais c'est une limitation connue et (seulement) 2 lignes de code doivent changer, il semble donc que cela semble être un compromis acceptable pour la propreté du code.
En ce qui concerne votre option 1 Suggestion: L'objectif est de fournir un accès non constitué aux membres privés de Chromosome. Si nous faisons le getter non-cons autres, une classe aléatoire pourrait jouer avec les privés de Chromsome. De toute évidence, je souhaite limiter cet accès uniquement à CrossSoverStrategy et à ses sous-classes. N'oubliez pas que nous prenons en effet ce qui était à l'origine chromosome :: crossover () et l'externalisant afin que nous puissions échanger avec différentes stratégies. Javascript le fait avec des fonctions anonymes mais je trouve C ++ Lamdbas laid et illisible par comparaison.
@Cridgit Quelles types de choses ne peuvent pas crossovertrategies code> faire avec
chromsome code>? Si la réponse n'est rien, voir si vous faites
chromsome code>
public code> et appliquer L'idiome PIMPL a du sens.
Le code comprend un exemple de ce qu'il a à voir avec le chromosome privés: "Parent1-> M_Genes [i] = 0,0;" Il doit accéder et modifier cela et peut-être d'autres membres privés. J'ai regardé Pimpl mais qui semble également cacher complètement les membres privés, alors je ne suis pas sûr de savoir comment je pourrais atteindre le résultat souhaité avec PIMPL, mais merci de la suggestion.
L'idée de PIMPL est la définition de la classe est uniquement exposée aux fichiers qui ont besoin de la définition. Tout le monde ne peut que voir et gérer une référence. Ils ne peuvent pas interagir avec l'objet lui-même. Donc, un Public code> Accès
chromosome code> permet à Direct, non
ami code> accès à ses internes à ceux qui ont une définition des internes et chacun d'autre < Code> Chromosome Code> pourrait aussi bien être entièrement
privé code> dès le bas aux constructeurs et aux fonctions des membres spéciaux.
Merci pour l'exemple complet - cela semble très approprié. Une petite question: si j'ai quelques méthodes publiques pour exposer par exemple. Chromosome :: getgenecount (), où puis-je faire cela sans casser le motif pimpl?
J'ai compris comment procéder à cela en utilisant votre exemple ci-dessus sur la base du motif PIMPL et c'est exactement ce que je cherchais. MERCI. J'ai utilisé une variable chromosomeimpl chromosomeimpl dans le fichier d'en-tête. Ensuite, j'ai effectué les membres chromosomeimpl au public dans le fichier source afin que seules les sous-classes de crossoverstrateggie vous accèdent. Fonctionne magnifiquement!
La première option évidente est de déterminer si les membres de Une deuxième option est pour alors tout Encapsulation de Il n'y a pas besoin d'une autre classe ou de fonction d'être un ami de Le compromis est que les gènes sont récupérés et des modifications en copiant l'ensemble complet (succès de la copie de performances potentielles). Mais il évite la nécessité de casser l'encapsulation de la classe code> chromosome code> en fournissant, directement ou indirectement, une référence à ses membres privés à toutes les autres classes. P> Si la copie de l'ensemble complet de Les chromosomes sont une mauvaise chose, entraînent des fonctions de membre supplémentaires de Si vous voulez vraiment, vous pouvez faire le SETTER et Getter De cette façon, seules les classes dérivées de chromosome code> doivent ou non être
public code>. Étant donné que vous souhaitez qu'un nombre arbitraire de classes aient accès à ses données, une option évidente est de rendre ces données
public code>.
chromosome code> à Fournissez un getter public et un réglage pour les données concernées, telles que; p>
crossoverstrategy code> et ses classes dérivées doivent faire, étant donné des pointeurs valides à
chromosome code> S, demande les gènes, faire tout ce qui est nécessaire, et (lors de la fin) fournit un nouvel ensemble de gènes à la sélection de chromosomes code>. p>
chromosome code> est préservé par diverses mesures, car le seul moyen de modifier les gènes est via une fonction de membre de
chromosome code>, c'est-à-dire qu'il n'y a aucun moyen de changer de gènes dans un chromosome à l'extérieur Contrôle de la classe code> chromosome code>. Qui permet à
chromosome code> de faire des chèques qu'il aime et rejeter les gènes bad si on le souhaitait. P>
Chromosome code>. Un avantage clé est qu'il n'est pas nécessaire de modifier la classe code> chromosome chromosome lorsque une nouvelle classe est dérivée de
crossoverstrategy code>. P>
chromosome code> qui permettent à l'appelant de demander des modifications partielles (par exemple, de mettre à jour des gènes particuliers, insérer un ensemble de gènes dans un endroit spécifié dans le vecteur des gènes, etc). Ces fonctions supplémentaires doivent fonctionner sur le même principe: tous les changements de gènes dans un
chromosome code> GO via des fonctions de membre de
chromosome code>, et il n'y a pas de mécanisme "porte arrière" pour les autres code pour se faufiler à travers. p>
privé code> membres de
chromosome code> et faire uniquement la classe de base
CrossOverStrategy Code> A
ami code>. Alors tous
crossoverstrategy code> doit fournir est fournir des aides
protégés code> qui n'appellent que les aides privés de
chromosome code>. P>
crossoverstrategy code> peuvent accéder aux aides code> protégés code>. Si le fonctionnement de
chromosome code> change, la seule classe à adapter dans ce cas est la base
crossoverstrategy code> classe - car ses classes dérivées n'accordent pas (directement) accès
chromosome code> du tout. p> p>
Peter merci pour cette réponse solide, il semble être le moyen le plus "correct" et certainement pas aussi laid que les 2 options que j'ai suggérées. J'attendrai de voir s'il y a une autre idée brillante avant d'accepter cela comme réponse.
Votre idée est fondamentalement défectueuse. P>
D'une part, vous dites que vous ne voulez pas juste n'importe qui em> pour être capable de jouer avec le vecteur de gènes. P>
D'autre part, vous voulez tout descendant em> de Mais il y a une contradiction. "Tout descendant" d'une classe est em> "juste n'importe qui". Tout utilisateur est capable d'hériter d'une classe et de faire ce qu'ils veulent avec votre vecteur de gènes. Ils n'ont besoin que de passer par un petit inconvénient à une fois d'héritage de C'est la raison pour laquelle l'amitié en C ++ n'est pas héritée. Si c'était le cas, le contrôle d'accès serait inutile en présence de classes d'amis. P>
Bien sûr, vous pouvez simuler une amitié héritable en ayant un getter protégé dans crossoverstrategy code> pour être capable de gâcher avec le vecteur de gènes. p>
crossoverstrategy code>. P>
crossoverstrategy code> comme l'une des réponses suggère. Mais cela défait le but du contrôle d'accès. Il rend les tableaux de gènes aussi bons que public. P>
Bien que je conviens que de faire des variables privées, le public doit être évité, sauf dans des circonstances spécifiques, l'encapsulation n'est pas binaire mais un spectre. Être capable d'accéder aux variables des membres en sous-classement, un ami est une étape supérieure à 100% d'accès public. Je ne suis donc pas d'accord pour que cela vaincra entièrement le but du contrôle d'accès - le concept a un certain mérite ci-dessus, ce qui rend tout public.
@Cridgit Je ne vois pas le spectre. L'accès est ouvert ou fermé. Il n'y a pas de demi-ouvert ou presque fermé.
Pas seulement laid, fatal. Tu ne retourneras pas la référence à la variable locale.
Bob est ton ami. Vous lui faites confiance avec vos secrets. Mais qu'en est-il de la pharmacie de Bob Dirtbag d'un fils, Griff? Faites-vous automatiquement confiance en griffon parce que vous faites confiance à Bob? Nan. Si les classes dérivées d'un
ami code> étaient automatiquement
ami code> s, vous pouvez sous-classer tout ce que vous vouliez et complètement schtroumpf sur encapsulation. Pas un bon plan.
Si vous ne pouvez pas éventuellement passer un pointeur nul pour un pointeur, envisagez de passer par des références au lieu des pointeurs. Tout sauf élimine les familles entières de becs accidentels.
Étant donné que vous souhaitez que plusieurs classes / fonction ont accès à des données qui constituent un
chromosome code>, pourquoi les données ne sont-elles pas
public code>?
@Peter parce que n'importe qui i> pourrait accéder aux données privées. Je préférerais que seul l'ami (et ses sous-classes) pouvait accéder. C'est une bonne option 3, mais le risque est que nous encapsulons entièrement du chromosome.
«Si seulement l'ami (et ses sous-classes». L'amitié n'est pas héritée précisément parce que n'importe qui i> peut créer une sous-classe de n'importe quoi. Avec votre système d'accès, vous avez une protection nulle.
Il y a toujours quelqu'un qui trouvera une raison de bowevote. Il est possible que la question laisse des informations importantes telles que "doit autoriser non-
const code> accès à des classes" et "d'autres classes doit pouvoir utiliser
chromosome code> de la manière suivante ... "Ce pourrait être la question est extrêmement spécifique à vos objectifs et de peu d'utilisation à quiconque et à" non utile ". Cela pourrait être quelque chose d'aussi trivial que l'exemple de code de travail ne fonctionne pas en raison d'un support égaré.
En pensant à cela plus, Engineering logiciel peut être meilleur ajustement pour cette question. Le débordement de la pile est généralement meilleur pour "pourquoi ça ne marche pas?" et soigneusement construit "Comment est-ce que je?" des questions. "Comment devrais-je?" est généralement dans le domaine de l'ingénierie. Notez que j'ai lié à la page d'aide sur la poser des questions. Il y a des attentes différentes de ce qui fait une bonne question.