Skip to content

Latest commit

 

History

History
432 lines (310 loc) · 12.8 KB

coaching_02.org

File metadata and controls

432 lines (310 loc) · 12.8 KB

G.Tech 1 – Projet#7 – C++ sous Linux / Git

Table of Contents

Organisation :TODOélèves:

URGENCE ABSOLUE: Élèves bloqués avec leur compte Windows non-admin

Groupe A seulement

Complétez le fichier “Consitution des binômes” avec votre login Windows et le nom de votre machine Windows sous la forme LOGIN@MACHINE.

On ne pourra pas avancer tant que cela ne sera pas réglé!

Votre espace de travail dans WSL :TODOélèves:

Votre espace de travail dans WSL doit être comme ceci:

Préférez des noms de dossiers/fichiers en minuscules!

# Liste des dossiers INDISPENSABLES:
~/proj7/
~/proj7/snake/         <- Résultat de la commande =cd ~/proj7/ ; git clone URL snake=
~/proj7/snake/ÉLÈVE1/
~/proj7/snake/ÉLÈVE2/

# Optionnel:
~/proj7/coach/

Si ce n’est pas le cas, corrigez-le sans délai.

Pour corriger, utiliser les commandes mv OLD_NAME NEW_NAME.

(Si vous avez des soucis pour renommer un dossier sous le Terminal VS Code, essayer avec le terminal WSL/Debian!)

Github.com en mode privé :TODOélèves:

  • Mon dépôt Github.com va passer en mode privé
  • Travailler avec un dépôt en mode publique est trop limitant: il va passer en mode privé
  • Vous allez être invités à utiliser mon dépôt, pour cela:

    Binômes/Trinômes: Dans le fichier “URL dépôts Github” du Drive: complétez les colonnes “Account 1” à “Account 3” avec le nom exact de votre compte Github.com, merci!

Cours: C++ & Programmation orientée objet

Introduction

  • C++ est une évolution du Langage C, il apporte la Programmation Orientée Objet (POO)

    Note: On peut mélanger du code C et C++

  • En POO, le paradigme change:
    • On utilise des classes pour définir des types complexes.
    • Analogie: Moule permettant de créer des objets semblables, mais chaque objet aura sa propre vie
  • Les classes contiennent:
    • Des membres qui sont des variables, elles-même d’un certain type (classe, int, char, etc.)
    • Des méthodes qui sont des fonctions dédiées et s’appliquent aux objet de la classe ou à la classe elle-même
  • Les classes étant un type, elles permettent de créer des variables, on les appelle objets:

    MaClasse mon_object;

  • Les Noms Des Classes Sont Prennent En Général Une Majuscule, Tout Comme Un Nom Propre. Ex: MaClasse, Animal, etc.

Exemple de classe

MaClasse contient:

  • Un nombre entier int a;, il est privé (personne ne peut y accéder à part l’objet)
  • Une méthode int add(int b); qui retourne a + b
    class MaClasse {
    public:
      int add(int b)  // méthode publique car définie dans le bloc 'public:'
      {
        // return a + b; // Accès implicite à =a=, on préfèrera =this->a=
        return this->a + b; // "this" est un pointeur sur l'objet lui-même, "->" permet d'accéder à ses membres
      }
    private:
      int a;          // membre privé car défini dans le bloc 'private:'
    }; // Ne pas oublier le ';' final !
    
    MaClasse obj;
    int c = obj.add(5);
        

Le parallèle entre C et C++ est relativement simple:

  • Type versus Classe:
    int x; // variable de type int
    
    MaClasse object; // object de type MaClasse
        
  • Fonction versus Méthode:
    int add(int a, int b) { return a + b; } // retourne a + b
    
    object.add(int b); // retourne object.a + b
        
  • Exemple concrêt: (Vu avec Groupe A seulement)
    class Rect {
    public:
      void move(int horiz, int vert) {
        this->c += horiz;
        this->l += vert;
        if (this->l < 0) {
          ...;
        }
      };
    
    private:
      int l, c; // coordonnées ligne, colonne
      uint8 R, V, B, ALPHA;
    };
    
    Rect r;
    r.move(5, 3);
    // r.V = 255; // Interdit car le membre V de la classe Rect est private!
        

Méthodes spéciales: Constructeur et Destructeur

class MClasse {
public:

  MClasse() {   // <- Constructeur, ici initialise le membre =a=
    this->a = 0;
  }

  MClasse(int a_) { // Second constructeur
    this->a = a_;
  }

  ~MClasse() {     // <- Destructeur, ici ne fait rien...
    printf("Détruit!");
  }

private:
  int a;
};

Simple et efficace:

  • Le Constructeur est appelé juste après que l’objet ait été créé en mémoire
  • Le Destructeur est appelé juste avant que l’objet ne soit détruit en mémoire

Vie et mort d’un object

  • Les objets peuvent être crées comme des variables dynamiques ou non:
    void some_code(void) {
      MaClasse obj1a; // Objet "statique", il mourra en fin du bloc de code {}
      // Notez comme ce constructeur ne prend pas de "()"
    
      // Variante avec arguments dans l'appel au constructeur:
      int valeur = 5;
      MaClasse obj1b(valeur); // Fait ceci: "obj1b.a = 5";
    
      MaClasse *obj2;
      obj2 = NULL;
      // ...
      obj2 = new MaClasse(); // Objet dynamique qu'il faudra détruire
      // ...
      if (obj2 != NULL)
        delete obj2;  // <- Appelle le Destructeur de l'objet
        // NE PAS FAIRE: =obj2->~MaClasse();=
    } // <- Au delà de ce bloc, obj1a et obj1b sont détruits ainsi que obj2
      // automatiquement car "statiques", ce n'est pas le cas de *obj2
        
  • Nous venons de voir les deux opérateurs:
    1. new permettant de créer un objet dynamiquement (donne un pointeur) Symboliquement équivalent à:
      1. obj2 = malloc(sizeof(MaClasse))
      2. puis appelle du Constructeur MaClasse()
    2. delete permettant de détruire un objet créé dynamiquement (via un pointeur seulement)
      1. Appelle le Destructeur ~MaClasse() et free(obj2)

Accès aux membres et méthodes d’un objet

class MClasse {
public:
  int a;             // <- Maintenant publique!
  int add(int b) { return this->a + b; }
};

// Cas avec objet "statique":
MaClasse obj1;
obj1.a = 1; // <- Accès OK si a est publique dans la classe MaClasse
int c = obj1.add(5);

// Cas avec objet "dynamique":
MaClasse *obj2 = new MaClasse();
obj2->a = 2; // Notation =obj2->a= équivalente à =(*obj2).a=
int d = obj2->add(3);

// Remarques: Un bon réflexe à avoir:
// objDyn->objStatique.a
// objDyn->objDyn->a

Droits d’accès: public et private

Dans une classe C++, on peut définir les droits d’accès aux membres et méthodes:

class MClasse {
public:
  int add(int b) {  // Cette méthode est publique et utilisable par n'importe quel code
    return this->a + b;
  }
  int GetA() {  // "Getter"
    return this->a;
  }
  int SetA(int a_) { // "Setter"
    if (a_ < 0 ){
      // ERREUR:
      return ...;
    }
    else
      this->a = a_;
  }

private:
  int a;  // Ce membre n'est accessible que par l'objet lui-même
};

// Illégal:
MClasse obj1;
int valeur = obj1.a; // ERREUR de compilation!!

MClasse *obj2 = new MClasse();
int valeur = obj2->a; // ERREUR de compilation!!

Note: Il existe également protected qui s’utilise prend son sens lorsqu’il y a héritage de classes, nous le verrons plus tard.

NEW Les 3 étapes de la compilation avec g++ (et gcc)

Quand on appelle g++ main.cpp snake.cpp -lSDL2 -o snake, il se passe trois choses:

  1. Le Preprocessing:
    • Modifie (en mémoire) les fichiers .hpp et .cpp avant la compilation (en étape 2)
    • Utilise les directives du type: #include, #define, #ifndef, #endif, etc.

      Par exemple: #define SIZE 3 a l’effet d’un Search/ReplaceAll sur les fichiers source dans lesquels on remplace tous les occurrences de SIZE par 3

  2. Compilation code source:
    • Analyse le code source –> Le transforme en code machine
    • Génère un fichier =.o= pour chaque fichier =.cpp=

      (Les fichiers .o sont parfois créés dans une zone temporaire, avec g++ ça se passe dans /tmp/...)

  3. L’Édition de liens (linkage effectué sous Linux ld):
    • Rassemble les fichiers .o (un par .cpp) et les assemble en un exécutable (ex: ./snake)

ATTENTION: Si:

  1. vous écrivez le code des fonctions/méthodes un fichier.hpp
  2. vous incluez #include "fichier.hpp" dans plusieurs fichiers .cpp
  3. vous compilez ces fichiers .cpp

Alors, vous aurez une erreur d’édition de lien car vos fonctions auront été comilées en langage machine (présentes dans les .o) autant de fois que vous aurez fait de #include "fichier.hpp"

Synthèse

g++ main.cpp snake.cpp -lSDL2 -o snake:

  1. Preprocessing des fichiers : main.cpp, snake.cpp, snake.hpp, SDL.h, etc.
  2. Traduction des fichiers

    main.cpp, snake.cpp –> main.o, snake.o

  3. Édition de liens

    main.o, snake.o, libSDL2 –> ./snake (exécutable)

NEW Séparation du code .hpp et .cpp

  • On met les déclarations dans les .hpp: class sans le code des méthodes
  • On protège le contenu de chaque fichier .hpp avec #pragma once:
    #pragma once # Permet de ne charger le fichier hpp qu'une seule fois
    
    // Mon contenu:
    #include <SDL2/SDL.h>
    // ...
    
    class ... {
    }
        
  • On met le code dans les .cpp, ex: int Maclasse::GetValue() { return this->value; }
  • On #include "..." tous nos fichiers .hpp dans nos .cpp
  • On compile en passant tous les .cpp à g++

NEW Qui va où dans mes fichiers .hpp, .cpp et main.cpp?

Dans mon fichier maclasse.hpp

=.hpp= = que du déclaratif

#ifndef MACLASSE_HPP
#define MACLASSE_HPP

#include <...>
#include "..." // Mes autres includes du projet si besoin

class MaClasse {
  MaClasse();
  ~MaClasse();
  void MyMeth();
  int *MyMeth2(int a);
};

#endif

Dans mon fichier maclasse.cpp

#include <...> // D'abord les include externes/système (=ceux qui ne sont pas à nous)
#include "maclasse.hpp"

MaClasse::MaClasse() {
  // ...
}

MaClasse::~MaClasse() {
  // ...
}

void MaClasse::MyMeth() {
  // ...
}

int *MaClasse::MyMeth2(int a) {
  // ...
}

Dans mon fichier main.cpp

#include <...> // D'abord les include externes/système (=ceux qui ne sont pas à nous)
#include "maclasse.hpp"

int main(void) {
  MaClasse obj;

  obj.MyMeth();
  int *c = obj.MyMeth2(4);
}

Cours: Révision Git (add, commit, push, etc.)

Voir fichier howto-git-everyday.org.

Exercices :TODOélèves:

Faites les exercices 1 et 2:

Voir les Ressources.

Objectifs pour le prochain coaching :TODOélèves:

  1. Terminez votre installation (machine G.Tech1 ou perso)

    Au besoin, consultez les divers Howto et la résolution des problèmes

  2. Terminez les exercices 1 à 3