Les membres privés dans les structures C
Cette semaine, ici à l'œuvre avait preuve de plus que paradigme de programmation est quelque chose de complètement indépendant de la langue, c'est à dire qu'elle n'est pas parce que vous programmez en C + +, la compilation avec g + + que votre code sera orienté objet, si peu, si vous programmez en C ANSI votre code doit être structurées ou il vous sera impossible à la programmation orientée objet.
Je suis en train de lire, Orientation objet en C ANSI?
Oui et non!
Des choses comme héritage, le polymorphisme et la surcharge sont plus difficiles à faire / émuler en C, mais vous pouvez programmer en utilisant un style qui se comporte de même de l'orienté objet. Le libdfb est écrit en C, mais «objet» orientés, de sorte que vous créer, de manipuler à détruire des éléments qui se comportent de manière similaire aux objets.
Ici, au travail, nous avons un système d'abstraction du matériel en C qui se connecte avec une interface graphique en C + +. La couche inférieure, a également été écrit en C (et très bien écrit, dit en passant) avec ces techniques, en simulant une orientation objet. Une de ces techniques, j'ai été frappé par le port de l'une de ces notes des livres de C.
Lors de la compilation de code C, chaque symbole n'est visible que dans l'unité de compilation dans laquelle elle a été déclarée, sauf s'il est de nouveau déclaré que extern dans les autres unités. Ainsi, il est possible de "cacher" certains symboles au sein de votre unité de compilation, les rendant inaccessibles au monde extérieur. Nous avons avec ce paquet.
Une unité de compilation est l'ensemble des fichiers qui code une fois transformés et pré-compilées génère un objet unique. Fondamentalement (mais pas exactement), nous pouvons prendre comme chaque unité de compilation de fichiers de mise en œuvre du code source (*. c, *. cpp. Etc). De plus amples détails sur les étapes de la compilation C et C + + peuvent être trouvés sur le blog Caloni .
Avec cette information, nous pouvons créer un C ANSI struct dont leurs membres internes sont «privées». La magie est dans la définition des états de pièges au sein de l'unité de compilation et de créer des méthodes d'accès pour ces membres. Pour cela, nous utilisons les notes qui nous montrent la différence entre la déclaration et la définition des éléments dans C:
Déclaration ou manifeste: le compilateur présente un identificateur sans dire beaucoup plus sur sa signification, soit indique au compilateur que l'identificateur XXX existe, mais on ne sait guère ce qu'il représente.
Par exemple:
a ; extern int a; void ) ; blah (void); st_data struct;
Définition ou mise en œuvre: indique au compilateur que l'identificateur est déterminée, comme la quantité de mémoire doit être attribué, et ce que l'adresse mémoire où l'on peut trouver, entre autres choses.
Par exemple:
int a; void ) { /* Do anything. blah (void) (/ * Ne rien. * /) /* Some members. st_data struct (/ * Ajouter membres. * /)
Quand on parle de structures et de types, sans régler le compilateur ne peut pas allouer de la mémoire pour eux, car on ne sait rien sur la façon dont l'espace d'une variable de type qui ont besoin. D'un autre côté, parfois sans la déclaration, l'éditeur de liens ne peut pas savoir ce que ce symbole existe.
Lorsque nous déclarons une structure dans un en-tête, en général, nous définissons également ses membres là-bas et chaque fois que nous ajoutons cet en-tête à une source de la nôtre, nous avons inclus dans l'unité de compilation que la source la déclaration que la définition de cette structure, ce qui rend les membres de l'ensemble de notre public à cette unité de compilation. Cela nous permet d'accéder directement à ses membres.
Si nous nous séparons de la déclaration de la définition, seul symbole qui représente la structure disponible, mais pas ses membres. Ainsi, toute tentative d'accès direct à un membre, va générer une erreur de compilation. Un effet secondaire intéressant est que le compilateur ne sait rien de la taille de la structure, vous ne pouvez pas définir directement une variable de structure type, seulement un pointeur vers elle, parce que les pointeurs ont tous la même taille et le compilateur n'a besoin que du nom du symbole Type de créer le pointeur.
Nous avons ensuite en-tête mytype.h comme ceci:
MY_TYPE_H # ifndef # Définir MY_TYPE_H / * Le typedef ne s'agit pas seulement de répéter le mot struct. * / / * La déclaration est que les mots: * / / * * Struct _mytype / typedef struct my_type _mytype; my_type ** ) ; create_my_type vide (my_type **); my_type ** ) ; destroy_my_type vide (my_type **); my_type * , int ) ; set_data void (* my_type, int); my_type * ) ; get_data int (* my_type); my_type * , const char * ) ; set_text void (* my_type, const char *); get_text ( my_type * ) ; get_text char * (* my_type); # Endif
La mise en œuvre mytype.c:
_mytype { /* Aqui fica a definição da estrtura. # Include "mytype.h" <stdio.h> # include # include # include <stdlib.h> <string.h> _mytype struct (/ * Voici la définition de estrtura. data ; /* Somente depois disso é que o com- */ int text [ 21 ] ; /* pilador vai saber como alocá-la. * / Int date; / * C'est seulement après que, avec-texte * / int [21] / * pilador saura renvoyer. ; /* Tente um sizeof(my_type) no main. * /), / * Essayez un sizeof (my_type) dans la fenêtre principale. create_my_type ( my_type ** my_ptr ) { /* some code... * / Create_my_type Void (my_ptr my_type **) (/ * un peu de code ... void destroy_my_type ( my_type ** my_ptr ) { /* some code... * /) Destroy_my_type Void (my_ptr my_type **) (/ * un peu de code ... void set_data ( my_type * my_ptr , int d ) { /* some code... * /) Set_data Void (* my_ptr my_type, int d) (/ * un peu de code ... int get_data ( my_type * my_ptr ) { /* some code... * /) Get_data Int (* my_ptr my_type) (/ * un peu de code ... void set_text ( my_type * my_ptr , const char * text ) { /* some code... * /) Set_text Void (* my_ptr my_type, const char * texte) (/ * un peu de code ... char * get_text ( my_type * my_ptr ) { /* some code... * /) Char * get_text (* my_ptr my_type) (/ * un peu de code ... * /)
Les exemples de code source complet se trouve ici .
Puisque vous ne pouvez pas créer directement des variables de ce genre, nous devons définir un «constructeur» et un destructeur ".
Les tentatives d'accès direct aux membres de générer d'erreur de compilation:
private-struct-members$ gcc -o teste mytype.h mytype.c main.c @ Hôte utilisateur: ~ / private-struct-membres gcc main.c-o test mytype.h $ mytype.c main.c: In function 'main': main.c: 22: erreur: déréférencement pointeur de type incomplet private-struct-members$ @ Hôte utilisateur: ~ / private-struct-membres $
Ainsi, avec un peu de créativité et de prendre les concepts de la langue comme deux paradigmes, vous pouvez appliquer des codes vraiment intéressant. Dans cet exemple stupide peut-être pas clairement l'utilité de forcer une émulation de l'encapsulation ou l'utilisation de constructeur / destructeur en C, mais dans les systèmes où les circonstances ne permettent pas de C + +, ou de la complexité tend à atteindre des niveaux critiques, ces techniques sont montrent d'une grande valeur. Dans notre cas, cette technique est autorisé spécifiquement un programmeur expérimenté, qui a raté la totalité du projet, il a découvert que sa tentative d'accès direct à un membre d'une structure, a été contextuellement inappropriée. Sans elle, une logique bug Kaboul semblerait que lors de l'exécution, ce qui rend le logiciel probablement exploser dans le visage du client.
Liens utiles (ou pas ...):
http://www.directfb.org
http://www.caloni.com.br
http://www.numaboa.com.br/informatica/c/
Linux Kernel développement Livre


