• Aucun résultat trouvé

5.4 - Organisation physique d'un objet

hp.top();

hp2.end();

for(i = 0; i < sz; i++) { cout << "hp = " << hp.read()

<< ", hp2 = " << hp2.read() << endl;

hp.next();

hp2.previous();

} } ///:~

Quand Pointerest déclaré, l'accès aux membres privés de Holderlui est accordé en disant :

friend struct Pointer;

struct Holdercontient un tableau de ints et Pointervous permet d'y accéder. Parce que Pointerest fortement lié avec Holder, il est judicieux d'en faire une structure membre de Holder. Mais comme Pointerest une classe différente de Holder, vous pouvez en créer plusieurs instances dans main( )et les utiliser pour sélectionner différentes parties du tableau. Pointerest une structure au lieu d'un simple pointeur C, donc vous pouvez garantir qu'il pointera toujours sans risque dans Holder.

La fonction memset( )de la bibliothèque C standard (dans <cstring>) est utilisée par commodité dans le programme ci-dessus. Elle initialise toute la mémoire démarrant à une certaine addresse (le premier argument) à une valeur particulière (le deuxième argument) sur noctets à partir de l'adresse de départ ( nest le troisième argument). Bien sûr, vous auriez pu simplement utiliser une boucle pour itérer sur toute la mémoire, mais memset(

)est disponible, abondamment testée (donc il est moins probable que vous introduisiez une erreur), et probablement plus efficace que si vous le codiez à la main.

5.3.2 - Est-ce pur ?

La définition de classe vous donne une piste de vérification, afin que vous puissiez voir en regardant la classe quelles fonctions ont la permission de modifier les parties privées de la classe. Si une fonction est friend, cela signifie que ce n'est pas un membre, mais que vous voulez quand-même lui donner la permission de modifier des données privées, et elle doit être listée dans la définition de la classe afin que tout le monde puisse voir que c'est une des fonctions privilégiées.

Le C++ est un langage objet hybride, pas objet pur, et le mot-clé frienda été ajouté pour régler certains problèmes pratiques qui ont surgi. Il n'est pas choquant de souligner que cela rend le langage moins "pur" car C++ estconçu pour être pragmatique, et non pas par pour aspirer à un idéal abstrait.

5.4 - Organisation physique d'un objet

Le chapitre 4 affirmait qu'un structécrit pour un compilateur C puis compilé avec C++ resterait inchangé. Cette affirmation faisait principalement référence à l'organisation physique d'un struct, c'est-à-dire à l'emplacement mémoire individuel des variables au sein de la mémoire allouée pour l'objet. Si le compilateur C++ modifiait l'organisation des structs conçus en C, alors tout code C que vous auriez écrit et qui serait basé sur la connaissance de l'emplacement précis des variables dans un structcesserait de fonctionner.

Cependant, quand vous commencez à utiliser des spécificateurs d'accès, vous entrez de plein pied dans le royaume du C++, et les choses changent un peu. Dans un "bloc d'accès" particulier (un groupe de déclarations

délimité par des spécificateurs d'accès), on a la garantie que les variables seront positionnées de manière contigües en mémoire, comme en C. Toutefois, les blocs d'accès peuvent ne pas apparaître au sein de l'objet dans l'ordre dans lequel vous les avez déclarés. Bien que le compilateur dispose en généralles blocs exactement comme vous les voyez, il n'y a pas de règles à ce sujet, car l'architecture d'une machine particulière et/ou d'un système pourrait avoir un support explicite des mots-clefs privateet protectedqui imposerait à ces blocs de se trouver dans des emplacements mémoires particuliers. Les spécifications du langage ne veulent pas priver une implémentation de ce type d'avantage.

Les spécificateurs d'accès font partie de la structure et n'affectent pas les objets créés à partir de la structure.

Toutes les informations relatives aux spécifications d'accès disparaissent avant que le programme ne soit exécuté ; en général, ceci se produit au moment de la compilation. Lors de l'exécution, les objets deviennent des "espaces de stockage" et rien de plus. Si vous le voulez vraiment, vous pouvez enfreindre toutes les règles et accéder directement à la mémoire, comme en C. C++ n'est pas conçu pour vous éviter de faire des choses imprudentes. Il vous fournit simplement une alternative bien plus simple, et autrement plus souhaitable.

En général, ce n'est pas une bonne idée de dépendre de quelque chose de spécifique à l'implémentation quand vous écrivez un programme. Quand vous devez avoir de telles dépendances, encapsulez-les dans une structure de façon à ce que les changements nécessaires au portage soient concentrés en un même endroit.

5.5 - La classe

Le contrôle d'accès est souvent appelé le masquage de l'implémentation. Inclure les fonctions dans les structures (souvent désigné par le terme encapsulation Comme nous l'avons dit précédemment, on appelle parfois le contrôle d'accès, l'encapsulation.)produisent un type de données avec des caractéristiques et des comportements, mais le contrôle d'accès impose des limites à ce type de données, pour deux motifs importants. La première est d'établir ce que le programmeur client peut et ne peut pas utiliser. Vous pouver construire vos mécanismes internes dans la structure sans vous soucier que des programmeurs clients pensent à ces mécanismes qui font partie de l'interface qu'ils devront employer.

Ceci amène directement la deuxième raison, qui est de séparer l'interface de l'implémentation. Si la structure est employée dans un ensemble de programmes, mais que les programmeurs clients ne peuvent faire rien d'autre qu'envoyer des messages à l'interface publique, alors vous pouvez changer tout ce qui est privé sans exiger des modifications à leur code.

L'encapsulation et le contrôle d'accès, pris ensemble, créent quelque chose de plus que la structC. Nous sommes maintenant dans le monde de la programmation orientée-objet, où une structure décrit une classe d'objets comme vous pouvez décrire une classe de poissons ou une classe d'oiseaux : Tout objet appartenant à cette classe partagera ces caractéristiques et comportements. C'est ce qu'est devenue la déclaration de structure, une description de la façon dont tous les objets de ce type agiront et à quoi ils ressembleront.

Dans le langage POO d'origine, Simula-67, le mot-clé classétait utilisé pour décrire un nouveau type de données.

Ceci a apparamment inspiré à Stroustrup de choisir le même mot-clé pour le C++, pour souligner que c'était le point focal de tout le langage : la création de nouveaux types de données qui sont plus que des structs C avec des fonctions. Cela semble être une justification adéquate pour un nouveau mot-clé.

Cependant, classest proche d'être un mot-clé inutile en C++. Il est identique au mot-clé structà tous les points de vue sauf un : les membres d'une classsont privatepar défaut, tandis que ceux d'une structsont public. Nous avons ici deux structures qui produisent le même résultat :

//: C05:Class.cpp

// Similarité entre une structure et une classe struct A {

private:

// On obtient des résultats identiques avec : class B {

La classe est le concept fondamental de la POO en C++. C'est un des mots-clés qui ne sera pasmis en gras dans ce livre – ça deviendrait fatigant avec un mot répété aussi souvent que “class.” Le changement avec les classes est si important que je suspecte que Stroustrup aurait préféré mettre définitivement aux clous la structure, mais le besoin de compatibilité ascendante avec le C ne permettait pas cela.

Beaucoup de personnes préfèrent un style de création de classe plutôt façon structque façon classe parce que vous surchargez le comportement privé par défaut de la classe en commençant par les éléments publics :

class X {

La logique sous-jacente est qu'il est plus sensé pour le lecteur de voir les membres qui ont le plus d'intérêt pour lui, ainsi il peut ignorer tout ce qui est privé. En effet, la seule raison pour laquelle tous les autres membres doivent être déclarés dans la classe est qu'ainsi le compilateur sait de quelle taille est l'objet et peut les allouer correctement, et ainsi peut garantir l'uniformité.

Les exemples de ce livre, cependant, mettront les membres privés en premier, comme ceci :

class X { void private_function();

int internal_representation;

public:

void interface_function();

};

Certains se donnent même la peine de décorer leurs propres noms privés :

class Y { public:

void f();

private:

int mX; // nom "décoré"

};

Comme mXest déjà caché dans la portée de Y, le m(pour “membre”) n'est pas nécessaire. Cependant dans les projets avec beaucoup de variables globales (quelque chose que vous devriez essayer d'éviter, mais qui est parfois inévitable dans des projets existants), il est utile de pouvoir distinguer dans une définition de fonction membre une donnée globale d'une donnée membre.