Partage de technologie

Classes et objets C (1)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Table des matières

Orienté processus et orienté objet

Programmation procédurale

Programmation orientée objet

1. Définition de la classe

Format de définition de classe

domaine de classe

2. Qualificateurs d'accès aux classes et encapsulation

qualificatif d'accès

encapsulation

3. Instanciation

notion d'instanciation

taille de l'objet

4. ce pointeur

Caractéristiques de ce pointeur


Orienté processus et orienté objet

  • Le langage C est un langage de programmation typique orienté processus. La conception du programme s'articule principalement autour des fonctions et des structures de données, en mettant l'accent sur le processus de mise en œuvre des fonctions.
  • C++ prend en charge la programmation procédurale et orientée objet. Les concepts de base de la programmation orientée objet incluent les classes, les objets, l'encapsulation, l'héritage et le polymorphisme, etc., qui rendent l'organisation et la conception du programme plus cohérentes avec le modèle du monde réel et améliorent la maintenabilité et l'évolutivité du code.

Programmation procédurale

La programmation orientée processus est une idée de programmation centrée sur les processus. Dans la programmation orientée processus, un programme est considéré comme un ensemble de fonctions ou de procédures exécutées dans un certain ordre pour accomplir une tâche spécifique.

avantage:

  • Performance efficace : Étant donné que la programmation orientée processus exécute directement les tâches en fonction du processus et ne nécessite pas de création et de gestion excessives d'objets, elle présente une efficacité d'exécution plus élevée dans certains scénarios avec des exigences de performances plus élevées, tels que la programmation système sous-jacente, la programmation intégrée, etc. Par exemple, dans le noyau du système d'exploitation, la programmation orientée processus peut être utilisée pour mieux optimiser les performances lors de la mise en œuvre de fonctions telles que la planification des processus et la gestion de la mémoire.
  • logique claire : Pour une logique de programme simple, il est mis en œuvre étape par étape selon le processus. La structure logique du code est claire et facile à comprendre, facile à comprendre et à maintenir. Par exemple, un programme simple qui calcule la somme de deux nombres peut définir directement une fonction de calcul à l'aide d'une programmation orientée processus.

défaut:

  • Mauvaise maintenabilité : Lorsque la taille du programme augmente et que les fonctions deviennent complexes, le code orienté programmation procédurale peut devenir difficile à maintenir et à étendre. Le couplage entre diverses fonctions étant élevé, la modification d’une fonction peut affecter d’autres fonctions associées.
  • Réutilisabilité du code faible: La réutilisation du code est généralement réalisée via des appels de fonction, mais pour les modules fonctionnels complexes, la réutilisation est plus difficile et les fonctions ne peuvent pas être bien encapsulées et abstraites.

Programmation orientée objet

La programmation orientée objet est une idée de programmation centrée sur l'objet. Les objets sont des entités qui contiennent des données (propriétés) et des méthodes (comportements) qui opèrent sur ces données. En encapsulant les données et les méthodes associées dans un objet, l'intégration des données et des opérations est réalisée.

avantage:

  • Haute maintenabilité : Encapsuler les fonctions dans des objets, en masquant l'implémentation interne des objets du monde extérieur et en réduisant le couplage entre les modules. Lorsqu'une fonction doit être modifiée, seule l'implémentation interne de l'objet correspondant doit être modifiée sans affecter les autres parties non liées. Par exemple, dans une application à interface graphique, si vous souhaitez modifier la fonction d'un bouton, il vous suffit de modifier la méthode correspondante de l'objet bouton sans affecter les autres éléments de l'interface.
  • Forte réutilisabilité du code : La réutilisation et l'expansion du code peuvent être facilement réalisées grâce à l'héritage, au polymorphisme et à d'autres fonctionnalités.Par exemple, créez une classe de baseShape(forme) puis en dériverCircle(rond),Rectangle(Rectangle) et d'autres sous-classes, les sous-classes peuvent réutiliser les attributs et méthodes de la classe de base et créer des extensions spécifiques.
  • Bonne flexibilité: La programmation orientée objet prend en charge le polymorphisme, qui permet au programme de sélectionner et d'exécuter dynamiquement les méthodes correspondantes en fonction du type réel de l'objet pendant l'exécution, augmentant ainsi la flexibilité et l'évolutivité du programme.

défaut:

  • Surcharge de performances: Étant donné que la création d'objets, l'appel de méthode et d'autres opérations nécessitent une certaine surcharge, dans certains scénarios avec des exigences de performances extrêmement élevées, cela peut affecter l'efficacité d'exécution du programme.
  • Coût d'apprentissage élevé: Les concepts et les fonctionnalités de la programmation orientée objet sont relativement complexes, ce qui rend leur apprentissage et leur compréhension difficiles pour les débutants.

1. Définition de la classe

Format de définition de classe

• class est le mot-clé qui définit la classe, Data est le nom de la classe et {} est le corps de la classe. Notez que le point-virgule final ne peut pas être omis à la fin de la définition de la classe. Le contenu du corps de la classe est appelé membres de la classe : les variables de la classe sont appelées attributs ou les variables membres de la classe, les fonctions de la classe sont appelées méthodes ou fonctions membres de la classe.

• Afin de distinguer les variables membres, il est généralement d'usage d'ajouter un identifiant spécial à la variable membre, comme commencer par _ ou m avant ou après la variable membre. Notez que ce n'est pas obligatoire en C++, il s'agit simplement de quelques conventions. .

• En C++, struct peut également définir des classes. C++ est compatible avec l'utilisation de struct en C. En même temps, struct a été mis à niveau vers une classe. Le changement évident est que les fonctions peuvent être définies dans struct. recommandé d'utiliser class pour définir les classes.

• Les fonctions membres définies dans une classe sont en ligne par défaut.

  1. class Date
  2. {
  3. public:
  4. void Init(int year, int month, int day)
  5. {
  6. _year = year;
  7. _month = month;
  8. _day = day;
  9. }
  10. private:
  11. // 为了区分成员变量,⼀般习惯上成员变量
  12. // 会加⼀个特殊标识,如_ 或者 m开头
  13. int _year; // year_ m_year
  14. int _month;
  15. int _day;
  16. };
  17. int main()
  18. {
  19. Date d;
  20. d.Init(2024, 3, 31);
  21. return 0;
  22. }

domaine de classe

• La classe définit une nouvelle portée. Tous les membres de la classe sont dans la portée de la classe. Lorsque vous définissez des membres en dehors de la classe, vous devez utiliser l'opérateur ::scope pour indiquer à quel domaine de classe appartient le membre.

• Le domaine de classe affecte les règles de recherche de compilation. Si Init dans le programme suivant ne spécifie pas le domaine de classe Stack, le compilateur traitera Init comme une fonction globale. Ensuite, lors de la compilation, la déclaration/définition des membres tels que le tableau ne peut pas être effectuée. trouvé, une erreur sera signalée. Spécifier le domaine de classe Stack signifie savoir qu'Init est une fonction membre. Si des membres tels qu'un tableau sont introuvables dans le domaine actuel, ils seront recherchés dans le domaine de classe.

  1. #include<iostream>
  2. using namespace std;
  3. class Stack
  4. {
  5. public:
  6. // 成员函数
  7. void Init(int n = 4);
  8. private:
  9. // 成员变量
  10. int* array;
  11. size_t capacity;
  12. size_t top;
  13. };
  14. // 声明和定义分离,需要指定类域
  15. void Stack::Init(int n)
  16. {
  17. array = (int*)malloc(sizeof(int) * n);
  18. if (nullptr == array)
  19. {
  20. perror("malloc申请空间失败");
  21. return;
  22. }
  23. capacity = n;
  24. top = 0;
  25. }
  26. int main()
  27. {
  28. Stack st;
  29. st.Init();
  30. return 0;
  31. }

2. Qualificateurs d'accès aux classes et encapsulation

qualificatif d'accès

• C++ est un moyen d'implémenter l'encapsulation, en utilisant des classes pour combiner les propriétés et les méthodes d'un objet afin de rendre l'objet plus complet et de fournir de manière sélective ses interfaces aux utilisateurs externes via des autorisations d'accès.

• Les membres modifiés par public sont directement accessibles en dehors de la classe ; les membres modifiés par protected et private ne sont pas directement accessibles en dehors de la classe. Protected et private sont identiques, et leurs différences seront reflétées dans le chapitre sur l'héritage plus tard.

• La portée des autorisations d'accès commence à partir de la position où le qualificatif d'accès apparaît jusqu'à ce que le qualificatif d'accès suivant apparaisse. S'il n'y a pas de qualificatif d'accès ultérieur, la portée se termine à }, c'est-à-dire la classe.

• Lorsqu'un membre de définition de classe n'est pas modifié par un qualificateur d'accès, sa valeur par défaut est privée.

• La structure est par défaut publique

• Généralement, les variables membres seront limitées à privées/protégées, et les fonctions membres qui doivent être utilisées par d'autres seront rendues publiques.

encapsulation

Les trois caractéristiques majeures de l'orientation objet : l'encapsulation, l'héritage et le polymorphisme.

Au stade des classes et des objets, nous étudions principalement les caractéristiques d'encapsulation des classes. Alors, qu'est-ce que l'encapsulation ?

Encapsulation : combinez de manière organique les données et les méthodes d'exploitation des données, masquez les propriétés et les détails d'implémentation de l'objet et exposez uniquement l'interface pour interagir avec l'objet.

L'encapsulation est essentiellement une sorte de gestion qui facilite l'utilisation des classes par les utilisateurs. Par exemple : pour un appareil complexe comme un ordinateur, les seules choses fournies à l'utilisateur sont les touches de mise sous et hors tension, la saisie au clavier, le moniteur, la prise USB, etc., permettant à l'utilisateur d'interagir avec l'ordinateur et d'effectuer ses tâches quotidiennes. Mais en réalité, le véritable travail de l’ordinateur réside dans le processeur, la carte graphique, la mémoire et les autres composants matériels.

Pour les utilisateurs d'ordinateurs, ils n'ont pas à se soucier des composants internes de base, tels que la disposition des circuits sur la carte mère, la conception du processeur, etc. Les utilisateurs ont seulement besoin de savoir comment allumer l'ordinateur et comment interagir avec l'ordinateur via le clavier et la souris. Par conséquent, lorsque les fabricants d'ordinateurs quittent l'usine, ils placent une coque à l'extérieur pour masquer les détails d'implémentation internes et ne fournissent que des interrupteurs d'alimentation, des prises pour souris et clavier à l'extérieur afin que les utilisateurs puissent interagir avec l'ordinateur.

Pour implémenter l'encapsulation dans le langage C++, les données et les méthodes d'exploitation des données peuvent être combinées de manière organique via des classes, et les droits d'accès peuvent être utilisés pour masquer les détails d'implémentation internes des objets et contrôler quelles méthodes peuvent être utilisées directement en dehors de la classe.

3. Instanciation

notion d'instanciation

• Le processus de création d'un objet dans la mémoire physique à l'aide d'un type de classe est appelé instanciation de classe.

• Une classe est une description abstraite d'un objet. C'est quelque chose comme un modèle, qui limite les variables membres de la classe. Ces variables membres sont uniquement déclarées et n'allouent pas d'espace lorsqu'un objet est instancié à l'aide d'un. classe.

• Une classe peut instancier plusieurs objets. Les objets instanciés occupent l'espace physique réel et stockent les variables membres de la classe. Par exemple : instancier des objets d'une classe, c'est comme utiliser des dessins de conception architecturale pour construire une maison dans la réalité. Une classe est comme un dessin de conception qui indique le nombre de pièces, la taille et les fonctions des pièces, etc., mais là. n'est pas un objet physique. Même si un bâtiment existe, il ne peut pas habiter des personnes. Ce n'est que lorsqu'une maison est construite avec des dessins de conception qu'elle peut être habitée. La même classe ressemble à un dessin de conception et ne peut pas stocker de données. L'objet instancié alloue de la mémoire physique pour stocker les données.

taille de l'objet

Analyser quels membres se trouvent dans l'objet de classe ? Chaque objet instancié par une classe possède un espace de données indépendant, l'objet doit donc contenir des variables membres. Les fonctions membres sont-elles donc incluses ? Premièrement, une fois la fonction compilée, il s'agit d'une section d'instructions qui ne peut pas être stockée dans l'objet. Ces instructions sont stockées dans une zone séparée (segment de code), donc si elles doivent être stockées dans l'objet, elles ne peuvent l'être. pointeurs vers les fonctions membres. Analysons à nouveau, est-il nécessaire de stocker des pointeurs dans l'objet ? Date instancie deux objets d1 et d2 ont tous deux leurs propres variables membres indépendantes _year/_month/_day pour stocker leurs propres données, mais la fonction membre Init/Print. les pointeurs de d1 et d2 sont les mêmes, donc les stocker dans des objets est inutile. Si vous utilisez Date pour instancier 100 objets, le pointeur de fonction membre sera stocké 100 fois, ce qui est trop inutile. En fait, le pointeur de fonction n'a pas besoin d'être stocké. Le pointeur de fonction est une adresse. La fonction appelante est compilée dans une instruction assembleur [adresse d'appel]. En fait, le compilateur doit trouver l'adresse de la fonction lors de la compilation et de la liaison. , pas au moment de l'exécution. Seul le polymorphisme dynamique est trouvé au moment de l'exécution et les adresses de fonction doivent être stockées.

Ci-dessus, nous avons analysé que seules les variables membres sont stockées dans les objets. C++ stipule que les objets instanciés par les classes doivent également respecter les règles d'alignement de la mémoire.

Règles d'alignement de la mémoire

Les règles d'alignement mémoire sont exactement les mêmes que celles du langage CArticle de référence :Langage C pour calculer l'alignement de la mémoire

Le premier membre est à l’adresse décalée de 0 par rapport à la structure.

• Les autres variables membres doivent être mappées à des adresses qui sont des multiples entiers d'un certain nombre (numéro d'alignement).

• Remarque : Logarithme = le plus petit entre le numéro d'alignement par défaut du compilateur et la taille du membre.

• Le logarithme par défaut dans VS est 8

• La taille totale de la structure est : un multiple entier du nombre d'alignement maximum (le plus grand de tous les types de variables et le plus petit paramètre d'alignement par défaut).

• Si une structure est imbriquée et que la structure imbriquée est alignée sur un multiple entier de son propre logarithme maximum, la taille globale de la structure est le nombre d'alignement maximum de tous les nombres (y compris l'alignement de la structure imbriquée).

S'il n'y a pas de variable membre, 1 octet doit être donné, car si même un octet n'est pas donné, comment peut-on montrer que l'objet a existé ? Ainsi, 1 octet est donné ici uniquement pour l'identification de l'existence de l'objet.

4. ce pointeur

Caractéristiques de ce pointeur

Il existe deux fonctions membres, Init et Print, dans la classe Date. Ainsi, lorsque d1 appelle les fonctions Init et Print, comment la fonction sait-elle si elle doit accéder à l'objet d1 ou. l'objet d2 ?Ensuite, nous verrons ici que C++ donne un pointeur this implicite pour résoudre le problème ici.

• Après la compilation du compilateur, les fonctions membres de la classe ajouteront par défaut un pointeur du type de classe actuel, appelé ce pointeur, à la première position du paramètre formel. Par exemple, le véritable prototype de la classe Init of Date est :void Init(Date* const this, int year, intmonth, int day) • Lors de l'accès aux variables membres dans les fonctions membres de classe, elles sont essentiellement accessibles via ce pointeur. Par exemple, lors de l'attribution d'une valeur à _year dans la fonction Init, this. -&gt;_année = année ;

• C++ stipule que ce pointeur ne peut pas être écrit explicitement à la place des paramètres réels et des paramètres formels (le compilateur le gérera lors de la compilation), mais ce pointeur peut être utilisé explicitement dans le corps de la fonction.

  1. #include<iostream>
  2. using namespace std;
  3. class Date
  4. {
  5. public:
  6. // void Init(Date* const this, int year, int month, int day)
  7. void Init(int year, int month, int day)
  8. {
  9. // 编译报错:error C2106: “=”: 左操作数必须为左值
  10. // this = nullptr;
  11. // this->_year = year;
  12. _year = year;
  13. this->_month = month;
  14. this->_day = day;
  15. }
  16. void Print()
  17. {
  18. cout << _year << "/" << _month << "/" << _day << endl;
  19. }
  20. private:
  21. // 这⾥只是声明,没有开空间
  22. int _year;
  23. int _month;
  24. int _day;
  25. };
  26. int main()
  27. {
  28. // Date类实例化出对象d1和d2
  29. Date d1;
  30. Date d2;
  31. d1.Init(2024, 7, 1); // d1.Init(&d1, 2024, 7, 1);
  32. d1.Print(); // d1.Print(&d1);
  33. d2.Init(2024, 7, 10); // d2.Init(&d2, 2024, 7, 10);
  34. d2.Print(); // d2.Print(&d2);
  35. return 0;
  36. }