• Aucun résultat trouvé

champ3 sont des erreurs à éviter à tout prix

Une classe est une entité complète, autonome, et le programmeur doit connaître à l’avance les membres qui la  composent.  

La seconde préoccupation est la visibilité de ces membres ; oublions les formules toutes faites "tous les champs  sont  privés  et  toutes  les  méthodes  sont  publiques".  La  réalité  est  toujours  plus  nuancée,  et  les  méthodes  d’accès ­ pour ne pas dire les propriétés ­ viennent rapidement contredire cette logique un peu simpliste. 

La  troisième  recommandation  est  l’ordre  dans  lequel  sont  définis  les  membres.  On  peut  commencer  par  les  champs, puis les constructeurs, puis les méthodes publiques, enfin les méthodes non publiques. Il ne faut pas se  priver de répéter pour chaque membre sa visibilité, ce qui évite des erreurs en cas de copier­coller intempestif.   Pour chaque méthode, on doit bien avoir à l’esprit si elle est statique, virtuelle, abstraite… Pour chaque champ, il  faut déterminer son type, son nom, sa visibilité s’il est statique, constant… 

La  dernière  recommandation  est  la  documentation.  Une  bonne  classe  doit  être  accompagnée  de  beaucoup  de  commentaires. Ceux­ci ne doivent pas reformuler en moins bien ce qui est écrit en C++, mais plutôt développer  des détails supplémentaires pour guider celui qui parcourt le code. 

Comme C++ sépare la définition de l’implémentation, cela constitue une "optimisation" pour le programmeur. Le  compilateur ne "moulinera" que les fichiers .cpp qui sont amenés à évoluer plus fréquemment que les fichiers .h,  normalement plus stables car issus de l’étape de conception. 

Le  langage  C++  propose  plusieurs  modes  d’héritage.  Le  plus  utilisé,  à  juste  titre,  est  l’héritage public. À quoi  peuvent bien servir les autres modes, comme l’héritage privé ?  

L’héritage  public  spécialise  une  classe.  La  classe  de  base  exprime  le  concept  le  plus  général,  le  plus  abstrait,  alors que les sous­classes vont plus dans le détail. Mais il existe toujours en principe une relation "est­un­cas­ particulier­de" entre la classe dérivée et la classe de base ; le livret est un cas particulier de compte. La voiture  est un cas particulier de véhicule…  

De  ce  fait  il  faut  se  méfier  des  constructions  syntaxiquement  possibles  mais  sémantiquement  insensées.  La  classe Chameau­Satellite  n’a sans doute pas grande utilité. Une applet ne peut être aussi une horloge est un  gestionnaire  de  souris.  Ces  constructions  amènent  de  la  complexité  et  produisent  des  programmes  difficiles  à  maintenir.  Faut­il  en  conclure  que  l’héritage  multiple  est  à  proscrire  ?  Sans  doute  pas.  C’est  un  mécanisme  indispensable  mais  qui  doit  être  envisagé  avec  des  précautions.  C++  étant  un  langage  général,  il  permet  l’héritage multiple, il en a même eu besoin pour la STL. Mais le programmeur doit être prudent s’il est amené à  recourir lui­même à cette construction. L’autre possibilité est de s’appuyer sur un framework qui prévoit l’héritage  multiple dans un contexte encadré, sans risque.  

Et  l’héritage  privé,  finalement  ?  Là  encore  il  s’agit  d’un  "truc"  pour  éviter  l’explosion  de  code  au  sein  d’un  programme complexe. Tous les membres devenant privés, ce n’est pas pour créer des méthodes virtuelles que  l’on recourt à ce mode. C’est pour repiquer du code sans trop s’embarrasser d’un quelconque polymorphisme.   De nos jours, il existe d’autres  façons  de  contrôler  la  quantité  de  code,  et  la  programmation  par  aspects  AOP  (Aspect­Oriented Programming) ouvre une voie prometteuse.  

Il existe des outils d’analyse de logiciels C++ (profilers) traquant les goulets de performances, les fuites mémoire  et  les  opérations  litigieuses.  Sous  Unix,  l’utilitaire  purify  sert  précisément  à  détecter  les  erreurs  d’implémentations d’un programme C++.   Comme C++ est un langage assez proche de la machine, on peut également employer sous Windows l’utilitaire  Process Viewer pour analyser le fonctionnement d’un programme. 

4. Y voir plus clair parmi les possibilités de l’héritage

5. Analyser l’exécution d’un programme C++

enidentnumber-AAEAAAD/////AQAAAAAAAAAMAgAAAE1FTkkuRWRpdGlvbnMuTUVESUFwbHVzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAUBAAAAJ0VOSS5FZGl0aW9ucy5NRURJQXBsdXMuQ29tbW9uLldhdGVybWFyawIAAAAHcGlzVGV4dAlwaWR0ZURhdGUBAA0CAAAABgMAAAA8NTI4MTQ0IC0gQWxnZXJpYSBFZHVjIC0gYWQwNWE2M2EtZGQ0Yi00ZGNkLWEzM2UtZGNjZWIzY2NiOTVlxA7dnxFVzogLAA==-enidentnumber

La  conception  d’un  programme  orienté  objet  en  C++  est  une  étape  qui  demande  une  certaine  maturation.  L’essence d’un tel programme ne tient pas seulement à l’implémentation des algorithmes qu’il contient, mais bien  à la structure des classes et aux relations qui les réunissent. Nous nous proposons dans cette partie de décrire  les approches de méthodes liées à la conception de programme C++. 

Avant  tout,  rappelons­nous  que  C++  a  été  créé  pour  créer  des  applications  à  destination  du  domaine  des  télécommunications. Ce langage n’est donc pas seulement un travail de recherche, mais c’est aussi le fruit d’un  travail  d’ingénierie  informatique.  Bien  entendu,  son  concepteur  Bjarne  Stroustrup  s’est  assuré  qu’il  était  suffisamment  général  pour  être  adapté  à  d’autres  situations.  Pour  atteindre  cet  objectif,  il  a  conçu  trois  éléments essentiels : 

La  méthode  proposée  par  Bjarne  Stroustrup  repose  évidemment  sur  son  expérience  de  conception  d’applications  antérieure  à  C++.  Elle  repose  sur  un  certain  nombre  de  thèmes  forts,  dont  certains  sont  des  classiques  des  méthodes  de  conception  logicielle,  orientée  objet  ou  pas.  Citons  parmi  ces  thèmes  la  délimitation du système, la complexité des applications par rapport au degré d’abstraction des outils, ou encore  les cycles de conception et de programmation perçus comme des activités itératives.  Le processus de développement minimal est constitué de trois étapes :  L’étape qui nous préoccupe est justement celle de la conception. L’auteur de la méthode organise des sous­ processus à partir du découpage suivant :  En conclusion, Bjarne Stroustrup a proposé une méthode générale, adaptée à la conception de programmes  C++. Il est vraisemblable que le langage lui­même a été influencé par la méthode de conception orientée objet.  Un des intérêts de l’approche décrite ci­dessus vient du fait qu’elle est compatible avec un système de notation  comme  UML.  De  fait,  UML  a  été  créé  à  une  époque  où  C++  était  l’un  des  rares  langages  de  programmation 

La conception orientée objet

1. Relation entre la POO et la COO (Conception Orientée Objet)

a. L’approche initiale de C++ ● 1. le langage C++ en lui­même.  ● 2. la bibliothèque standard S.T.L.  ● 3. une méthode de conception orientée objet pour C++.  ● 4. analyse  ● 5. conception  ● 6. implémentation  ● identification des classes, des concepts et de leurs relations les plus fondamentales ;  ● spécification des opérations, c’est­à­dire des méthodes ;  ● spécification des dépendances (des cardinalités dirait­on en UML) ;  ● identification des interfaces pour les classes les plus importantes ;  ● réorganisation de la hiérarchie des classes ;  ● utilisation de modèles pour affiner le diagramme.  b. UML et C++ enidentnumber-AAEAAAD/////AQAAAAAAAAAMAgAAAE1FTkkuRWRpdGlvbnMuTUVESUFwbHVzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAUBAAAAJ0VOSS5FZGl0aW9ucy5NRURJQXBsdXMuQ29tbW9uLldhdGVybWFyawIAAAAHcGlzVGV4dAlwaWR0ZURhdGUBAA0CAAAABgMAAAA8NTI4MTQ0IC0gQWxnZXJpYSBFZHVjIC0gYWQwNWE2M2EtZGQ0Yi00ZGNkLWEzM2UtZGNjZWIzY2NiOTVlyKe3qRFVzogLAA==-enidentnumber

orientée objet disponibles pour l’industrie.  

UML  est  l’acronyme d’Unified  Modeling  Language. Il s’agit  d’un  formalisme  qui  unifie  les  travaux  en  matière  de  conception  orientée  objet  développés  pour  la  plupart  au  cours  des  années  70  et  80.  Ce  formalisme  est  à  l’initiative d’une société, Rational, qui a ensuite proposé le logiciel de modélisation Rose, ainsi qu’une méthode  à part entière appelée RUP (Rational Unified Process). 

Comme C++ était l’un des principaux langages du marché, il a fortement influencé l’élaboration d’UML.  Aussi,  est­il  fréquent  de  trouver  des  logiciels  de  modélisation  UML  capables  de  transformer  automatiquement  un  diagramme de classes en programme C++, sans toutefois pouvoir fournir l’implémentation correspondante !  Le  formalisme  UML  est  constitué  de  neuf  diagrammes.  Il  n’est  souvent  pas  nécessaire d’exécuter  l’ensemble  des diagrammes pour parvenir à une modélisation conforme. Par contre, certains diagrammes nécessitent de  s’y prendre en plusieurs fois. On parle alors d’un processus de modélisation itératif.  Voici la liste des diagrammes constitutifs du formalisme UML 1 :  Des outils tels que Visio Architect ou Enterprise Architect sont capables de reproduire le diagramme de classes  d’un programme, ou inversement de générer du C++ à partir d’un diagramme de classes.  Comme UML et C++  sont deux langages très généraux, ils s’entendent parfaitement et toute la panoplie du C++ peut être écrite en  UML. 

Le diagramme de classe suivant montre comment modéliser une partie du tableur 

CLIMulticube

 étudié au 

chapitre  Les  univers  de  C++.  C’est  bien  la  preuve  que  le  formalisme  UML  n’est  aucunement  réservé  aux  langages C# ou Java.  Diagramme des cas  d’utilisations  Vision  fonctionnelle  Pose les limites du système en listant les acteurs et  leurs intentions, sans s’attarder sur le "comment".   Diagramme de  collaboration  Vision  fonctionnelle 

Les  cas  d’utilisations  sont  décrits  sous  la  forme  de  scénarii  textuels  avant  d’être  formalités  en  diagrammes  de  collaboration.  C’est  le  début  du  comment. 

Diagramme d’activité  Vision 

fonctionnelle 

C’est  une  version  "workflow"  du  diagramme  de  collaboration  plus  adaptée  à  la  description  de  certains scénarii. 

Diagramme état­ transition 

Vision  dynamique 

C’est  une  version  technique  d’un  workflow  ;  on  considère des changements d’état au sein de classes  qui prennent progressivement forme. 

Diagramme de séquence  Vision 

dynamique 

Semblable  au  diagramme  d’état  transition,  le  diagramme  de  séquence  étudie  la  constitution  de  classe  sous  l’angle  du  temps,  en  faisant  progressivement ressortir des méthodes.  

Diagramme du domaine  Vision "métier"  Ce  diagramme  ne  fait  pas  partie  d’UML  mais  il  est  indispensable.  Les  classes  métiers  sont  souvent  structurées à partir des tables SQL. 

Diagramme de classes  Vision statique  Ce  diagramme  est  un  peu  la  version  affinée, 

superposée des précédents diagrammes.   Diagramme de 

composants 

Vision système  Lorsque  les  classes  sont  stéréotypées,  pourvues 

d’interfaces  techniques,  elles  sont  appelées 

composants.   Diagramme de 

déploiement 

Vision système  Ce  diagramme  précise  sur  quels  nœuds  les 

composants doivent être déployés.  enidentnumber-AAEAAAD/////AQAAAAAAAAAMAgAAAE1FTkkuRWRpdGlvbnMuTUVESUFwbHVzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAUBAAAAJ0VOSS5FZGl0aW9ucy5NRURJQXBsdXMuQ29tbW9uLldhdGVybWFyawIAAAAHcGlzVGV4dAlwaWR0ZURhdGUBAA0CAAAABgMAAAA8NTI4MTQ0IC0gQWxnZXJpYSBFZHVjIC0gYWQwNWE2M2EtZGQ0Yi00ZGNkLWEzM2UtZGNjZWIzY2NiOTVlyKe3qRFVzogLAA==-enidentnumber

Les  design  patterns  sont  des  façons  standard  d’aborder  des  problèmes  logiciels.  Il  s’agit  de  constructions  de  classes répertoriées que l’on adapte (développe) au gré des besoins.  

Nous  avons  vu  au  chapitre  Les  univers  de  C++  que  les  MFC  implémentaient  le  pattern  MVC  (Modèle  Vue  Contrôleur) à travers l’architecture document vue. Il existe de très nombreux modèles et certains générateurs de  code peuvent constituer l’ossature d’une application en paramétrant des patterns pour un langage donné.  Pour  illustrer  les  patterns,  nous  développons  l’exemple  du  Singleton.  Il  s’agit  de  veiller  à  ce  qu’une  classe  ne  puisse  être  instanciée  qu’une  et  une  seule  fois.  Un  exemple  habituel  d’utilisation  de  ce  pattern  concerne  les  fichiers de configuration qui ne doivent pas exister en plusieurs exemplaires au sein d’une application. 

class Configuration {

private:

static Configuration* instance; Configuration()

{

// Le constructeur privé empêche toute instanciation externe à la classe

}

public:

static Configuration* getInstance() {

if(instance==NULL) {

printf("Instanciation de Configuration\n"); instance = new Configuration();

} return instance; } public: bool param1,param2; } ; Configuration* Configuration::instance=NULL;

int _tmain(int argc, _TCHAR* argv[]) {

// utilisation du singleton

Configuration::getInstance()->param1 = true;

2. Les design patterns

Configuration::getInstance()->param2 = true;

return 0; }

Comme le constructeur est privé, il est impossible d’instancier la classe 

Configuration

 en dehors de celle­ci. 

Cependant,  nous  pouvons  confier  cette  instanciation  à  une  méthode  publique  et  statique, 

getInstance()

Cette dernière s’appuie sur un champ statique, 

instance

, pour contrôler l’unique instanciation de la classe. Au 

premier  appel  de 

getInstance()

,  le  champ 

instance

  égale 

NULL

  et  la  classe  est  instanciée.  Tous  les 

Documents relatifs