1. Introduction au C++



sommaire chapitre 1

1.8. Méthodes virtuelles : classes abstraites, interfaces

1.8.1. Méthode virtuelle

Une méthode virtuelle est une méthode dont l'implantation peut être adaptée/redéfinie dans une classe héritée.

Elle est déclarée en préfixant la méthode par le mot clé virtual

Sur l'exemple suivant on déclare un classe Person, puis une classe Student qui hérite de Person. La méthode d'affichage est virtuelle car elle va dépendre de la classe. Note : on réutilise la partie liée à l'affichage de Person.

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4.  
  5. /**
  6.  * Base class
  7.  */
  8. class Person {
  9. protected:
  10.     string name;
  11.     int age;
  12. public:
  13.     // default constructor
  14.     Person() {
  15.         name = "";
  16.         age = 0;
  17.     }
  18.    
  19.     // constructor with 2 arguments
  20.     Person(string n, int a) {
  21.         name = n;
  22.         age = a;
  23.     }
  24.        
  25.     // display class
  26.     virtual ostream& print(ostream& out) {
  27.         out << name << ", " << age;
  28.         return out;
  29.     }
  30.    
  31.     friend ostream& operator<<(ostream& out, Person& p) {
  32.         return p.print(out);
  33.     }
  34. };
  35.  
  36. /**
  37.  * Inherited class with redefinition of virtual method print
  38.  */
  39. class Student : public Person {
  40. protected:
  41.     string level;
  42.    
  43. public:
  44.     Student(string n, int a, string l) : Person(n, a), level(l) {
  45.     }
  46.    
  47.     ostream& print(ostream& out) {
  48.         Person::print(out);
  49.         out << ", level = " << level;
  50.         return out;
  51.     }
  52. };
  53.  
  54. int main() {
  55.     Person p("toto", 10);
  56.     Student s("john", 20, "l3 informatique");
  57.    
  58.     cout << p << endl;
  59.     cout << s << endl;
  60.    
  61.     return 0;
  62. }
  63.  
  64.  
toto, 10
john, 20, level = l3 informatique

1.8.2. Méthode virtuelle pure : classe abstraite

Une méthode virtuelle pure est une méthode virtuelle sans corps (code).

Elle est déclarée en préfixant la méthode par le mot clé virtual et en la suffixant par = 0;

Une classe qui possède une méthode virtuelle pure ne peut pas être instanciée ce qui permet de déclarer une classe mère dite abstraite dont le but sera de définir les méthodes à implanter dans les classes filles.

  1. class Abstraite {
  2. public:
  3.     Abstraite() { }
  4.     virtual void methode() = 0;
  5. };
  6.  
  7. int main() {
  8.     // not possible
  9.     //Abstraite a;
  10.  
  11.     // possible
  12.     Abstraite *a;
  13.    
  14.     // not possible
  15.     //a = new Abstraite();
  16.     return 0;
  17. }
  18.  

1.8.3. Interface

Une interface représente un ensemble de méthodes dont dispose une classe.

Par définition : une interface dispose uniquement de méthodes et pas de données membres, mais en C++ on peut inclure des données membres. Remarque : ce n'est pas le cas en Java.

On dit qu'une classe implémente/implante une interface.

En C++, la notion d'interface n'existe pas de manière native puisque seule la classe permet de déclarer des méthodes héritées mais également des données membres. C'est donc au programmeur qu'est laissée la responsabilité de créer des interfaces en s'assurant de ne pas ajouter de données membres à la classe qu'il veut faire apparaître comme interface.

Deux classes qui implantent la même interface peuvent donc être manipulées de la même manière.

Sur l'exemple suivant on crée une interface pour une pile et deux implémentations différentes :

On montre alors comment manipuler les deux piles au travers de l'interface pour s'affranchir de l'implémentation.

interface

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4.  
  5. /**
  6.  * interface of a stack
  7.  */
  8. class IntegerStackInterface {
  9. public:
  10.     // add value on top
  11.     virtual void push(int value)  = 0;
  12.     // remove value on top
  13.     virtual void pop() = 0;
  14.     // return value on top
  15.     virtual int top() = 0;
  16.     // tells whether stack is empty
  17.     virtual bool is_empty() = 0;
  18. };
  19.  
  20. /**
  21.  * Implementation as a C array
  22.  */
  23. class IntegerStackAsArray : public IntegerStackInterface {
  24. protected:
  25.     int max_elements;
  26.     int index;
  27.     int *elements;
  28. public:
  29.     IntegerStackAsArray(int sz=10) {
  30.         index = -1;
  31.         elements = new int [max_elements = sz];
  32.     }
  33.     ~IntegerStackAsArray() {
  34.         delete [] elements;
  35.     }
  36.     void push(int value) {
  37.         elements[++index] = value;
  38.     }
  39.     void pop() {
  40.         --index;
  41.     }
  42.     int top() {
  43.         return elements[index];
  44.     }
  45.     bool is_empty() {
  46.         return (index == -1) ? true : false;
  47.     }
  48. };
  49.  
  50. /**
  51.  * Implementation as a STL vector
  52.  */
  53. class IntegerStackAsVector : public IntegerStackInterface {
  54. protected:
  55.     int max_elements;
  56.     vector<int> v;
  57. public:
  58.     IntegerStackAsVector(int sz=10) {
  59.         max_elements = sz;
  60.     }
  61.     ~IntegerStackAsVector() {
  62.    
  63.     }
  64.     void push(int value) {
  65.         v.push_back(value);
  66.     }
  67.     void pop() {
  68.         v.pop_back();
  69.     }
  70.     int top() {
  71.         return v[v.size()-1];
  72.     }
  73.     bool is_empty() {
  74.         return (v.size() == 0) ? true : false;
  75.     }
  76.    
  77. };
  78.  
  79. /**
  80.  * treatment using pointer access
  81.  * add values 1, 2, ..., 10
  82.  * then compute sum by poping them
  83.  */
  84. void process_ptr(IntegerStackInterface *s) {
  85.     for (int i=1; i<=10; ++i) {
  86.         s->push(i);
  87.     }
  88.     int sum = 0;
  89.     while (!s->is_empty()) {
  90.         sum += s->top();
  91.         s->pop();
  92.     }
  93.     cout << "sum = " << sum << endl;
  94. }
  95.  
  96. /**
  97.  * treatment using reference access
  98.  * add values 1, 2, ..., 10
  99.  * then compute sum by poping them
  100.  */
  101. void process_ref(IntegerStackInterface& s) {
  102.     for (int i=1; i<=10; ++i) {
  103.         s.push(i);
  104.     }
  105.     int sum = 0;
  106.     while (!s.is_empty()) {
  107.         sum += s.top();
  108.         s.pop();
  109.     }
  110.     cout << "sum = " << sum << endl;
  111. }
  112.  
  113.  
  114. int main() {
  115.     IntegerStackAsArray s1;
  116.     IntegerStackAsVector s2;
  117.    
  118.    
  119.     process_ptr(&s1);
  120.     process_ptr(&s2);
  121.    
  122.     process_ref(s1);
  123.     process_ref(s2);
  124. }
  125.  
  126.  
  127.