Maison > Java > javaDidacticiel > Orientation objet en C ? Implémentation d'une interface à partir de zéro.

Orientation objet en C ? Implémentation d'une interface à partir de zéro.

Mary-Kate Olsen
Libérer: 2025-01-21 10:05:12
original
700 Les gens l'ont consulté

Orientação a Objetos em C? Implementando uma interface do zero.

J'ai toujours été curieux des ordinateurs et j'ai toujours pensé : "D'accord, je sais comment l'utiliser, mais comment ça marche vraiment ? Dans ce processus, je fais souvent une expérience de pensée : si on me demandait de commencer par ?" En partant de zéro, que ferais-je ? Dans cet article, nous explorerons le fonctionnement des interfaces dans la programmation orientée objet (en utilisant Java), puis implémenterons une version modeste de l'interface en C.

Regardons un exemple

Notre exemple est simple : calculer le prix d'un véhicule. S'il s'agit d'une voiture, le prix sera basé sur sa vitesse de pointe ; s'il s'agit d'une moto, le prix sera basé sur sa cylindrée. On définit d'abord le comportement du véhicule à l'aide d'une interface :

<code class="language-java">public class Main {
    public interface Vehicle {
        Integer price();
    }
}</code>
Copier après la connexion
Copier après la connexion

Rien de spécial ici, juste une méthode qui renvoie un entier. Implémentons maintenant la classe car :

<code class="language-java">public class Main {
    // ...

    public static class Car implements Vehicle {
        private final Integer speed;

        public Car(Integer speed) {
            this.speed = speed;
        }

        @Override
        public Integer price() {
            return speed * 60;
        }
    }
}</code>
Copier après la connexion
Copier après la connexion

Très classique : une mise en place d'une méthode constructeur et prix, multipliant la vitesse par 60. Maintenant, implémentons la classe moto :

<code class="language-java">public class Main {
    // ...

    public static class Motorcycle implements Vehicle {
        private final Integer cc;

        public Motorcycle(Integer cc) {
            this.cc = cc;
        }

        @Override
        public Integer price() {
            return cc * 10;
        }
    }
}</code>
Copier après la connexion
Copier après la connexion

Presque pareil, la seule différence est que maintenant on multiplie le déplacement par 10. Ensuite, nous mettons en œuvre une méthode pour imprimer le prix du véhicule :

<code class="language-java">public class Main {
    // ...

    public static void printVehiclePrice(Vehicle vehicle) {
        System.out.println("$" + vehicle.price() + ".00");
    }
}</code>
Copier après la connexion
Copier après la connexion

Pas de secrets. Enfin, notre méthode principale :

<code class="language-java">public class Main {
    // ...

    public static void main(String[] args) {
        Car car = new Car(120);
        Motorcycle motorcycle = new Motorcycle(1000);

        printVehiclePrice(car);
        printVehiclePrice(motorcycle);
    }
}</code>
Copier après la connexion
Copier après la connexion
<code>$ java Main.java
00.00
000.00</code>
Copier après la connexion
Copier après la connexion

C'est le modèle que nous souhaitons réaliser, mais maintenant implémenté à partir de zéro en C.

Comment pouvons-nous résoudre ce problème ?

Quand je pense aux objets, la première chose qui me vient à l'esprit est un ensemble de données qui représentent un état et des méthodes pour faire fonctionner et gérer cet état. La manière la plus directe de représenter une collection de données en langage C est une structure. Pour les méthodes, l’approche la plus proche est une fonction qui reçoit un état en paramètre. Cet état correspondra à cela dans la classe, par exemple :

<code class="language-c">typedef struct {
    int height_in_cm;
    int weight_in_kg;
} Person;

float person_bmi(Person *person) {
    float height_in_meters = (float)person->height_in_cm / 100;
    float bmi =
        (float)person->weight_in_kg / (height_in_meters * height_in_meters);

    return bmi;
}</code>
Copier après la connexion
Copier après la connexion

Ici, nous définissons les données d'une personne dans la structure Personne et utilisons ces données pour effectuer des calculs simples. C'est la structure la plus proche d'une classe que nous puissions avoir en C. Peut-être qu'utiliser des pointeurs de fonction dans les structures est également une bonne idée ? Eh bien, je laisse cela pour le prochain article.

D'accord, nous avons une structure semblable à celle d'une classe. Maintenant, comment définissons-nous l’interface en langage C ? Si vous y réfléchissez bien, le compilateur/interprète ne fait pas de magie pour deviner quelles classes implémentent l'interface. Il le détermine au moment de la compilation et remplace toutes les parties où nous utilisons l'interface par des types concrets. Dans le programme compilé, l'interface n'existe même pas.

Le compilateur du langage C n'offrant pas cette possibilité, nous devons implémenter cette solution nous-mêmes. Nous devons connaître tous les types qui implémentent notre interface et comprendre comment utiliser les fonctions de ces implémentations.

Implémenter l'interface en langage C

Tout d’abord, définissons le squelette de notre humble interface. Nous allons créer une énumération qui contient les différentes implémentations et signatures de nos fonctions.

<code class="language-java">public class Main {
    public interface Vehicle {
        Integer price();
    }
}</code>
Copier après la connexion
Copier après la connexion

Ici, nous définissons notre énumération qui contient l'implémentation que nous implémenterons plus tard. Cela ne semble peut-être pas le cas, mais cette partie est très importante. Ensuite, nous déclarons la fonction Vehicle_free (qui sera expliquée plus tard) et la fonction Vehicle_price, que nous voulons implémenter dans notre "classe". Regardons maintenant l'implémentation de la voiture :

<code class="language-java">public class Main {
    // ...

    public static class Car implements Vehicle {
        private final Integer speed;

        public Car(Integer speed) {
            this.speed = speed;
        }

        @Override
        public Integer price() {
            return speed * 60;
        }
    }
}</code>
Copier après la connexion
Copier après la connexion

La fonction car_init initialise un nouvel "objet" Car en mémoire. En Java, cela se fera automatiquement via new. Ici, nous devons le faire manuellement. La fonction vehicle_free sera utilisée pour libérer la mémoire allouée par tout "objet" précédemment initialisé, implémenté à l'aide de car_free etc. La mise en œuvre pour les motos est très similaire :

<code class="language-java">public class Main {
    // ...

    public static class Motorcycle implements Vehicle {
        private final Integer cc;

        public Motorcycle(Integer cc) {
            this.cc = cc;
        }

        @Override
        public Integer price() {
            return cc * 10;
        }
    }
}</code>
Copier après la connexion
Copier après la connexion

Presque pareil, sauf que maintenant on initialise avec VEHICLE_MOTORCYCLE et on multiplie par 10. Regardons maintenant la fonction qui imprime le prix du véhicule :

<code class="language-java">public class Main {
    // ...

    public static void printVehiclePrice(Vehicle vehicle) {
        System.out.println("$" + vehicle.price() + ".00");
    }
}</code>
Copier après la connexion
Copier après la connexion

C'est si simple... on dirait que nous ne faisons pas beaucoup de travail. Maintenant, le dernier et le le plus important point est que nous devons implémenter les fonctions que nous avons déclarées dans la définition de l'interface ci-dessus, vous vous souvenez ? Heureusement, nous n’avons même pas besoin de penser à cette mise en œuvre. Nous avons toujours un simple interrupteur/boîtier exhaustif et c'est tout.

<code class="language-java">public class Main {
    // ...

    public static void main(String[] args) {
        Car car = new Car(120);
        Motorcycle motorcycle = new Motorcycle(1000);

        printVehiclePrice(car);
        printVehiclePrice(motorcycle);
    }
}</code>
Copier après la connexion
Copier après la connexion

Maintenant, nous pouvons utiliser tout ce que nous avons fait :

<code>$ java Main.java
00.00
000.00</code>
Copier après la connexion
Copier après la connexion
<code class="language-c">typedef struct {
    int height_in_cm;
    int weight_in_kg;
} Person;

float person_bmi(Person *person) {
    float height_in_meters = (float)person->height_in_cm / 100;
    float bmi =
        (float)person->weight_in_kg / (height_in_meters * height_in_meters);

    return bmi;
}</code>
Copier après la connexion
Copier après la connexion

Succès ! Mais vous pensez peut-être : « Eh bien, à quoi ça sert ? »

Un vrai cas d'usage

L'un de mes types de projets préférés est celui des analyseurs, des analyseurs aux simples analyseurs d'expressions mathématiques. Généralement, lorsque vous implémentez ces analyseurs, vous rencontrez quelque chose appelé AST (Abstract Syntax Tree). Comme son nom l'indique c'est un arbre qui va représenter la syntaxe à laquelle vous avez affaire, par exemple la déclaration de variable int foo = 10 est un nœud de l'AST qui contient trois autres nœuds, un nœud de type, pour int, un nœud identifiant ; , pour foo, et un nœud d'expression, pour 10, qui contient un autre nœud entier avec une valeur de 10. Vous voyez à quel point c'est compliqué ?

Quand nous faisons cela en C, nous devons choisir entre une énorme structure avec plusieurs champs pour représenter n'importe quel nœud AST possible, ou une définition abstraite utilisant plusieurs petites structures, chaque structure représente des nœuds différents, tout comme nous le faisons ici avec notre "interfaces". Si vous voulez voir un exemple simple, dans cet analyseur d'expressions mathématiques, j'ai implémenté la deuxième approche.

Conclusion

Rien de ce qu'un compilateur ou un interprète fait n'est magique. C'est toujours un exercice amusant d'essayer de mettre en œuvre quelque chose soi-même. J'espère que cette lecture a été utile. Merci!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal