C++

🚀 IntermĂ©diaire

Templates (ModĂšles)

Les templates permettent d'écrire du code générique qui fonctionne avec différents types.

Templates de fonction

#include <iostream> template <typename T> T maximum(T a, T b) { return (a > b) ? a : b; } int main() { std::cout << maximum(10, 20) << std::endl; // int std::cout << maximum(3.14, 2.71) << std::endl; // double std::cout << maximum('a', 'z') << std::endl; // char return 0; }

Templates de classe

#include <iostream> template <typename T> class Boite { private: T contenu; public: Boite(T val) : contenu(val) {} T getContenu() { return contenu; } void setContenu(T val) { contenu = val; } }; int main() { Boite<int> boiteInt(42); Boite<std::string> boiteStr("Hello"); std::cout << boiteInt.getContenu() << std::endl; std::cout << boiteStr.getContenu() << std::endl; return 0; }

Héritage et polymorphisme

Héritage simple

#include <iostream> #include <string> class Animal { protected: std::string nom; int age; public: Animal(std::string n, int a) : nom(n), age(a) {} virtual void faireDuBruit() { std::cout << "L'animal fait du bruit" << std::endl; } void afficher() { std::cout << nom << ", " << age << " ans" << std::endl; } }; class Chien : public Animal { public: Chien(std::string n, int a) : Animal(n, a) {} void faireDuBruit() override { std::cout << "Woof! Woof!" << std::endl; } }; class Chat : public Animal { public: Chat(std::string n, int a) : Animal(n, a) {} void faireDuBruit() override { std::cout << "Miaou!" << std::endl; } }; int main() { Chien rex("Rex", 3); Chat felix("Felix", 2); rex.afficher(); rex.faireDuBruit(); felix.afficher(); felix.faireDuBruit(); // Polymorphisme Animal* animal = &rex; animal->faireDuBruit(); // Woof! Woof! return 0; }
💡 Astuce : Le mot-clĂ© virtual permet le polymorphisme. Utilisez override pour indiquer qu'une mĂ©thode redĂ©finit une mĂ©thode virtuelle.

Smart Pointers

Les smart pointers gÚrent automatiquement la mémoire et évitent les fuites mémoire.

unique_ptr

#include <iostream> #include <memory> class Personne { public: std::string nom; Personne(std::string n) : nom(n) { std::cout << "Création de " << nom << std::endl; } ~Personne() { std::cout << "Destruction de " << nom << std::endl; } }; int main() { std::unique_ptr<Personne> p1 = std::make_unique<Personne>("Alice"); std::cout << p1->nom << std::endl; // p1 sera automatiquement libéré à la fin du scope return 0; }

shared_ptr

#include <iostream> #include <memory> int main() { std::shared_ptr<int> p1 = std::make_shared<int>(42); std::cout << "Compteur: " << p1.use_count() << std::endl; // 1 { std::shared_ptr<int> p2 = p1; std::cout << "Compteur: " << p1.use_count() << std::endl; // 2 } // p2 détruit ici std::cout << "Compteur: " << p1.use_count() << std::endl; // 1 return 0; }

Gestion des exceptions

#include <iostream> #include <stdexcept> double diviser(double a, double b) { if (b == 0) { throw std::runtime_error("Division par zéro!"); } return a / b; } int main() { try { double resultat = diviser(10, 2); std::cout << "Résultat: " << resultat << std::endl; resultat = diviser(10, 0); // Lance une exception std::cout << "Ceci ne s'affichera pas" << std::endl; } catch (const std::runtime_error& e) { std::cout << "Erreur: " << e.what() << std::endl; } catch (...) { std::cout << "Erreur inconnue" << std::endl; } std::cout << "Programme continue..." << std::endl; return 0; }

Exceptions personnalisées

#include <iostream> #include <exception> class MonException : public std::exception { private: std::string message; public: MonException(const std::string& msg) : message(msg) {} const char* what() const noexcept override { return message.c_str(); } }; void verifierAge(int age) { if (age < 18) { throw MonException("Vous devez ĂȘtre majeur!"); } } int main() { try { verifierAge(15); } catch (const MonException& e) { std::cout << e.what() << std::endl; } return 0; }

Lambdas et fonctions

Expressions lambda

#include <iostream> #include <vector> #include <algorithm> int main() { // Lambda simple auto saluer = []() { std::cout << "Bonjour!" << std::endl; }; saluer(); // Lambda avec paramĂštres auto additionner = [](int a, int b) { return a + b; }; std::cout << additionner(5, 3) << std::endl; // Capture de variables int multiplicateur = 10; auto multiplier = [multiplicateur](int x) { return x * multiplicateur; }; std::cout << multiplier(5) << std::endl; // Utilisation avec STL std::vector<int> nombres = {1, 2, 3, 4, 5}; std::for_each(nombres.begin(), nombres.end(), [](int n) { std::cout << n * 2 << " "; }); return 0; }

Move semantics et rvalue references

#include <iostream> #include <vector> #include <string> class Donnees { private: std::vector<int> data; public: // Constructeur Donnees(size_t taille) : data(taille) { std::cout << "Constructeur" << std::endl; } // Copy constructor Donnees(const Donnees& autre) : data(autre.data) { std::cout << "Copy constructor" << std::endl; } // Move constructor Donnees(Donnees&& autre) noexcept : data(std::move(autre.data)) { std::cout << "Move constructor" << std::endl; } // Copy assignment Donnees& operator=(const Donnees& autre) { std::cout << "Copy assignment" << std::endl; data = autre.data; return *this; } // Move assignment Donnees& operator=(Donnees&& autre) noexcept { std::cout << "Move assignment" << std::endl; data = std::move(autre.data); return *this; } }; int main() { Donnees d1(1000); Donnees d2 = std::move(d1); // Move constructor return 0; }

Multithreading de base

#include <iostream> #include <thread> #include <mutex> #include <vector> std::mutex mtx; int compteur = 0; void incrementer(int n) { for (int i = 0; i < n; i++) { std::lock_guard<std::mutex> lock(mtx); compteur++; } } int main() { std::vector<std::thread> threads; // Créer 5 threads for (int i = 0; i < 5; i++) { threads.push_back(std::thread(incrementer, 1000)); } // Attendre tous les threads for (auto& t : threads) { t.join(); } std::cout << "Compteur final: " << compteur << std::endl; return 0; }
⚠ Compilation : Pour utiliser les threads, compilez avec l'option -pthread

Exercices pratiques

  1. Créez un template de classe Liste chaßnée générique
  2. Implémentez un systÚme de formes géométriques avec héritage et polymorphisme
  3. Développez un gestionnaire de tùches avec smart pointers
  4. Créez un programme de traitement d'images parallÚle avec threads
  5. Implémentez un cache thread-safe avec mutex