Interface c++

shad - 2 mars 2015 à 20:25
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 - 6 mars 2015 à 11:51
Bonjour à tous,

voila j'ai une question dont je n'arrive pas à trouver la solution sur google. Je débute en c++ et j'aimerais savoir ce qu'est une interface ? et sa définition.

Merci :)

3 réponses

BunoCS Messages postés 15472 Date d'inscription lundi 11 juillet 2005 Statut Modérateur Dernière intervention 25 mars 2024 103
3 mars 2015 à 08:54
Bonjour,

D'après Wikipedia: http://fr.wikipedia.org/wiki/Interface_%28programmation_orient%C3%A9e_objet%29

En gros, l'interface de ta classe est composée des méthodes/fonctions publiques de celle-ci, celles que tu peux appeler à partir d'une autre classe.
0
yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 26
5 mars 2015 à 22:34
Salut,

Une interface est un paradigme permettant de faire "implémenter" des fonctions "sans corps" à une classe qui l'utiliserait.

En conception objet, une interface ne peut contenir aucun attribut, évènement ect... Seulement des prototypes de méthode.
En c++ ce n'est pas vraiment le cas car il n'existe pas de mot clef "interface", on utilise donc la notion de classe abstraite.

Par exemple,
une implémentation d'une interface ISerializable n'a de sens que si les 2 méthodes suivantes sont définies :
Save() et Load()

Une objet serializable est un objet qui maintient sa valeur entre chaque allocation/libération

class ISerializable
{
  public:
    virtual void Save(FILE* hFile) = 0;
    virtual void Load(FILE* hFile) = 0;
};

class MonObjet : public ISerializable
{
    private:
        int _data;
    public:
      MonObjet() { _data = 0; }
      MonObjet(int data) { _data=data; }

      void Save(FILE* hFile) { fwrite(&_data, sizeof(int), 1, hFile); fclose(hFile); }
      void Load(FILE* hFile) { fread(&_data, sizeof(int), 1, hFile); fclose(hFile); }
};

// Crée un objet et sauve son état
MonObjet objet( 9999 );
objet.Save( fopen("test.txt", "wb") );


// Ailleur ou plus tard,  remonte l'objet à son état antérieur
MonObjet* sameObjet = new MonObjet;
sameObjet->Load( fopen("test.txt", "rb")  );
// (...) utilise
delete sameObjet;


bye...
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 6/03/2015 à 11:52
@yann_lo_san:
Ta réponse est techniquement correcte, mais on évite pourtant de faire cela :(. Le souci d'utiliser du "virtual", c'est que ce n'est pas "gratuit". Quand on veut appliquer une contrainte conceptuelle, ça ne doit être qu'une vue de l'esprit et ne pas affecter les performances. Le virtual introduit un petit overhead (un pointeur en plus pour la vtable et des accès aux méthodes très légèrement plus lente). De plus, une méthode virtuelle ne peut plus être inliné. Ce n'est pas très cher si tu n'es pas dans un contexte de haute performance (utilisation d'un appel de fonction virtuelle au sein d'une boucle très très utilisé par exemple), mais c'est dommage que le concept puisse affecter les performances (même faiblement).

Bien évidemment, il existe une solution pour avoir le beurre et l'argent du beurre ! On utilise pour cela un CRTP (curiously recurring template pattern) pour faire du pseudo model checking. La technique consiste à utiliser un template pour lui faire vérifier la présence de certaines méthodes. Le template ne faisant rien, le compilateur le retira lors de la passe d'optimisation. C'est donc "gratuit". Le seul petit défaut (même souci que pour la class abstraite au final), c'est que le compilateur ne préviendra que le modèle n'est pas respecté, uniquement lorsque tu essaieras d'instancier l'objet.

#include <iostream>
#include <unistd.h>
#include <stdio.h>

/*
L'astuce consiste à déclarer un pointeur sur fonction sur
une méthode qu'on considère présente. Si celle-ci n'est pas
là, la compilation échouera.
*/

template <typename T>
struct ISerializable
{
  typedef T super;

  ISerializable()
  {
    void (super::*checkSave)(FILE* file) = &super::save;
    void (super::*checkLoad)(FILE* file) = &super::load;
    checkSave = checkSave; // Avoid warning
    checkLoad = checkLoad;
  }
};

class MonObjet : public ISerializable<MonObjet>
{
public:
  MonObjet() : _data(0) {}
  MonObjet(int data) : _data(data) {}

  void save(FILE* file) { fwrite(&_data, sizeof(int), 1, file); fclose(file); }
  void load(FILE* file) { fread(&_data, sizeof(int), 1, file); fclose(file); }

protected:
  int _data;
};

class MonObjetIncompatible : public ISerializable<MonObjetIncompatible>
{
public:
  void test() {  }
};


int main()
{
  MonObjet objet(9999); // Ok !
  objet.save( fopen("test.txt", "wb") );
  // Ailleur ou plus tard,  remonte l'objet à son état antérieur
  MonObjet* sameObjet = new MonObjet;
  sameObjet->load(fopen("test.txt", "rb"));
  delete sameObjet;

  MonObjetIncompatible obj; // Oupss, ne compilera pas.

  return 0;
}


2ème remarque:
Le design de code de l'exemple choisi est un peu maladroit. En effet, en C++, pour tout ce qui est flux on utilise un design un peu plus élégant. On utilise un std::ostream (qui représente un flux quelconque), et on y met dedans le flux choisi (fichier, console, socket, pipe, etc...).

Exemple:
#include <iostream>
#include <fstream>

class MonObjet
{
public:
  MonObjet() : _data(0) {}
  MonObjet(int data) : _data(data) {}

  void save(std::ostream& out) const { out << _data; }
  void load(std::ostream& in) { in >> _data; }

private:
  int _data;
};

int main()
{
  std::ofstream file("toto.txt");
  MonObjet obj(56);

  obj.save(std::cout);
  obj.save(file);

  obj.load(std::cin);
  obj.load(file);

  // envoyer sur le réseau, un pipe, etc... ? => obj.save(socket), obj.save(pipe), etc...

  return 0;
}



Améliorer votre expérience CodeS-SourceS avec ce plugin:
ttp://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
0
Rejoignez-nous