web-dev-qa-db-fra.com

Le terme "interface" en C ++

Java fait une distinction claire entre class et interface. (Je crois que c # fait aussi, mais je n'ai aucune expérience avec elle). Lorsque vous écrivez C++, mais il n'y a pas de distinction appliquée par une langue entre la classe et l'interface.

Par conséquent, j'ai toujours considéré l'interface comme une solution de contournement pour le manque d'héritage multiple en Java. Rendre une telle distinction se sent arbitraire et sans signification en C++.

J'ai toujours eu tendance à aller avec l'approche "écrire de la manière la plus évidente", donc si dans C++ j'ai ce qu'on pourrait appeler une interface en Java, par exemple:

class Foo {
public:
  virtual void doStuff() = 0;
  ~Foo() = 0;
};

et j'ai alors décidé que la plupart des exécutants de Foo souhaitaient partager certaines fonctionnalités courantes que j'écrirais probablement:

class Foo {
public:
  virtual void doStuff() = 0;
  ~Foo() {}
protected:
  // If it needs this to do its thing:
  int internalHelperThing(int);
  // Or if it doesn't need the this pointer:
  static int someOtherHelper(int);
};

Qui rend alors cela pas une interface dans le Java sens.

Au lieu de cela, C++ a deux concepts importants, liés au même problème de succession sous-jacent:

  1. virtual Inhéric
  2. Les classes sans variables de membre ne peuvent occuper aucun espace supplémentaire lorsqu'ils sont utilisés comme base

    "Les sous-observations de la classe de base peuvent avoir une taille de zéro"

    Référence

Parmi ceux que j'essaye d'éviter le n ° 1 dans la mesure du possible - il est rare de rencontrer un scénario où cela est véritablement le design "plus propre". # 2 est toutefois une différence subtile, mais importante entre ma compréhension du terme "interface" et les fonctionnalités de langue C++. À la suite de cela, je n'ai actuellement jamais référence à des "interfaces" en C++ et à parler en termes de classes de base et à leurs tailles. Je dirais que dans le contexte de la "interface" C++, c'est un abu.

Il est venu à mon attention que peu de gens ne font pas une telle distinction.

  1. Est-ce que je reste à perdre quoi que ce soit en permettant (par exemple protected) non - virtual fonctions d'exister dans une "interface" en C++? (Mon sentiment est exactement le contraire - un emplacement plus naturel pour le code partagé)
  2. Est-ce que le terme "interface" significatif dans c ++ - il implique-t-il seulement pur virtual ou serait-il juste d'appeler des classes C++ sans variables de membre une interface encore?
11
Flexo

En C++, le terme "interface" n'a pas seulement ne de définition largement acceptée - donc chaque fois que vous allez l'utiliser, vous devez dire ce que vous voulez dire exactement - une classe de base virtuelle avec ou sans implémentations par défaut, un fichier d'en-tête, les membres du public d'une classe arbitraire et ainsi de suite.

En ce qui concerne votre exemple: In Java (et similaire en C #), votre code impliquerait probablement une séparation des préoccupations:

interface IFoo {/*  ... */} // here is your interface

class FooBase implements IFoo 
{
     // make default implementations for interface methods
}

class Foo extends FooBase
{
}

En C++, vous CAN Le faire, mais vous n'êtes pas obligé de. Et si vous souhaitez appeler une interface de classe une classe une classe si elle n'a pas de variables de membre, mais contient des implémentations par défaut pour certaines méthodes, faites-le simplement, mais assurez-vous que tout le monde auquel vous parlez connaît ce que vous voulez dire.

11
Doc Brown

Cela semble un peu comme si vous êtes peut-être tombé dans le piège de déranger la signification de ce qu'il est qu'une interface est conceptuellement comme une implémentation (l'interface - minuscule 'i') et une abstraction (une interface - majuscule 'i' ).

En ce qui concerne vos exemples, votre premier bit de code est simplement une classe. Pendant que votre classe a une interface dans le sens où il fournit des méthodes permettant d'accéder au comportement de son comportement, ce n'est pas une interface Dans le sens d'une déclaration d'interface qui fournit une couche d'abstraction représentant un type de comportement que vous pouvez vouloir que des classes implémentent. Doc Brown's Réponse à votre message montre que vous parlez exactement de quoi je parle ici.

Les interfaces sont souvent introduites comme "Travailler" pour les langues qui ne soutiennent pas de multiples héritages, mais je pense que c'est plus une idée fausse qu'une vérité difficile (et je soupçonne que je peux me faire enflammer cela!). Les interfaces n'ont vraiment rien à voir avec de multiples héritages en ce sens qu'ils ne nécessitent ni être hérité, ni être un ancêtre afin de fournir une compatibilité fonctionnelle entre les classes ou l'abstraction de mise en œuvre pour les classes. En fait, ils peuvent vous permettre de supprimer efficacement l'héritage si vous souhaitez mettre en œuvre votre code de cette façon - et non que je le recommanderais tout à fait, mais je ne dis que vous pourrait fais-le. Donc, la réalité est que, quels que soient des questions d'héritage, les interfaces fournissent un moyen par lequel les types de classe peuvent être définis, établissant les règles qui déterminent comment les objets peuvent communiquer entre eux, ils vous permettent donc de déterminer le comportement que vos classes devraient soutenir sans dicter la méthode spécifique utilisée pour mettre en œuvre ce comportement.

Dois-je perdre quoi que ce soit en permettant (par exemple les fonctions protégées) non virtuelles d'exister dans une "interface" en C++? (Mon sentiment est exactement le contraire - un emplacement plus naturel pour le code partagé)

Une interface pure est censée être entièrement abstraite, car elle permet de définition un contrat de compatibilité entre les classes qui auraient peut-être nécessairement hérité de leur comportement d'un ancêtre commun. Lors de la mise en œuvre, vous souhaitez choisir d'autoriser la prolongation du comportement de mise en œuvre dans une sous-classe. Si vos méthodes ne sont pas virtual, vous perdez la possibilité d'étendre ce comportement plus tard si vous décidez que vous devez créer des classes de descendance. Que la mise en œuvre soit virtuelle ou non, l'interface définit la compatibilité comportementale en soi, tandis que la classe fournit la mise en œuvre de ce comportement pour les instances que la classe représente.

Est-ce que le terme "interface" significatif en C++ - ne signifie-t-il que du virtuel pur ou serait-il juste d'appeler des classes C++ sans variables de membre une interface encore?

Pardonne-moi, mais cela fait longtemps que j'ai vraiment écrit une application sérieuse en C++. Je me souviens que l'interface est un mot-clé aux fins de l'abstraction que je les ai décrites ici. Je n'appelerais pas les classes C++ de toutes sortes d'interface, je dirais plutôt que la classe a une interface dans les significations que j'ai décrites ci-dessus. Dans ce sens, le terme IS _ significatif, mais cela dépend vraiment du contexte.

7
S.Robins

Les interfaces Java ne sont pas une "solution de contournement", ils constituent une décision de conception délibérée visant à éviter certains des problèmes de multiples héritage comme héritage de diamant et d'encourager les pratiques de conception qui minimisent le couplage.

Votre interface avec des méthodes protégées est un cas de manuel de nécessité de "préférer la composition sur l'héritage". Pour citer Sutter et Alexandrescu dans la section par ce nom de leur excellente C++ Coding Normes :

Évitez les impôts de succession: l'héritage est la deuxième relation de couplage la plus serrée en C++, deuxième uniquement à l'amitié. Le couplage serré n'est pas souhaitable et doit être évité si possible. Par conséquent, préférez la composition à l'héritage à moins que vous sachiez que ce dernier profite vraiment à votre conception.

En incluant vos fonctions d'assistance dans votre interface, vous pouvez enregistrer une petite frappe maintenant, mais vous introduisez un couplage qui vous fera mal à la route. Il est presque toujours meilleur à long terme pour que votre assistant fonctionne séparer et transmettre un Foo*.

La STL est un très bon exemple de cela. Au fur et à mesure que de nombreuses fonctions d'assistant que possible, sont retirées dans <algorithm> Au lieu d'être dans les classes de conteneur. Par exemple, puisque sort() utilise l'API de conteneur public pour effectuer ses travaux, vous savez que vous pouvez implémenter votre propre algorithme de tri sans avoir à modifier de code STL. Cette conception permet aux bibliothèques telles que Boost, qui améliorent la STL au lieu de le remplacer, sans que la STL n'a besoin de savoir quoi que ce soit sur Boost.

6
Karl Bielefeldt

Dois-je perdre quoi que ce soit en permettant (par exemple les fonctions protégées) non virtuelles d'exister dans une "interface" en C++? (Mon sentiment est exactement le contraire - un emplacement plus naturel pour le code partagé)

Vous penseriez que, mais mettre en place une méthode protégée et non virtuelle dans une classe autrement abstraite dicte la mise en œuvre à quiconque écrit une sous-classe. Cela défait le but d'une interface dans son sens pur, qui est de fournir à un placage qui cache ce qui est en dessous.

C'est l'une de ces cas où il n'y a pas de réponse unique et vous devez utiliser votre expérience et votre jugement pour prendre une décision. Si vous pouvez dire avec 100% de confiance que chaque sous-classe possible de votre classe de votre classe sinon-virtuelle Foo aura toujours besoin d'une implémentation de la méthode protégée bar(), alors Foo est le bon endroit pour cela. Une fois que vous avez une sous-classe Baz qui n'a pas besoin bar(), vous devez soit vivre avec le fait que Baz aura accès au code que cela ne devrait pas à travers l'exercice de réorganisation de votre hiérarchie de classe. Le premier n'est pas une bonne pratique et ce dernier peut prendre plus de temps que les quelques minutes qu'il aurait prises d'organiser des choses correctement en premier lieu.

Est-ce que le terme "interface" significatif en C++ - ne signifie-t-il que du virtuel pur ou serait-il juste d'appeler des classes C++ sans variables de membre une interface encore?

La section 10.4 de la norme C++ fait une mention de passage de l'utilisation de classes abstraites pour mettre en œuvre des interfaces mais ne les définit pas officiellement. Le terme est significatif dans un contexte général de l'informatique et que toute personne compétente devrait comprendre que "Foo est une interface pour (peu importe)" implique une forme d'abstraction. Ceux qui sont exposés aux langues avec des constructions d'interface définies pourraient penser pur virtuel, mais quiconque a besoin de travailler avec Foo examinera sa définition avant de procéder.

2
Blrfl