Interface c++

- - Dernière réponse : cptpingu
Messages postés
3801
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
15 novembre 2019
- 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 :)
Afficher la suite 

3 réponses

Messages postés
14658
Date d'inscription
lundi 11 juillet 2005
Statut
Modérateur
Dernière intervention
15 novembre 2019
90
0
Merci
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.
Commenter la réponse de BunoCS
Messages postés
1137
Date d'inscription
lundi 17 novembre 2003
Statut
Membre
Dernière intervention
23 janvier 2016
17
0
Merci
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...
Commenter la réponse de yann_lo_san
Messages postés
3801
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
15 novembre 2019
90
0
Merci
@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
Commenter la réponse de cptpingu