web-dev-qa-db-fra.com

Pourquoi avons-nous réellement besoin d'un héritage privé ou protégé en C ++?

En C++, je ne peux pas penser à un cas dans lequel je voudrais hériter privé/protégé d'une classe de base:

class Base;
class Derived1 : private Base;
class Derived2 : protected Base;

Est-ce vraiment utile?

57
Gal Goldman

Il est utile lorsque vous souhaitez avoir accès à certains membres de la classe de base, mais sans les exposer dans l'interface de votre classe. L'héritage privé peut également être considéré comme une sorte de composition: la C++ faq-lite donne l'exemple suivant pour illustrer cette déclaration

class Engine {
 public:
   Engine(int numCylinders);
   void start();                 // Starts this Engine
};

class Car {
  public:
    Car() : e_(8) { }             // Initializes this Car with 8 cylinders
    void start() { e_.start(); }  // Start this Car by starting its Engine
  private:
    Engine e_;                    // Car has-a Engine
};

Pour obtenir la même sémantique, vous pouvez également écrire la classe de voiture comme suit:

class Car : private Engine {    // Car has-a Engine
 public:
   Car() : Engine(8) { }         // Initializes this Car with 8 cylinders
   using Engine::start;          // Start this Car by starting its Engine
}; 

Cependant, cette façon de faire présente plusieurs inconvénients:

  • votre intention est beaucoup moins claire
  • cela peut conduire à un héritage multiple abusif
  • il rompt l'encapsulation de la classe Engine puisque vous pouvez accéder à ses membres protégés
  • vous êtes autorisé à remplacer les méthodes virtuelles du moteur, ce que vous ne voulez pas si votre objectif est une composition simple
44
Luc Touraille

Le privé peut être utile dans plusieurs circonstances. Un seul d'entre eux sont des politiques:

La spécialisation de modèle de classe partielle est-elle la réponse à ce problème de conception? .

Une autre occasion où il est utile est d'interdire la copie et l'attribution:

struct noncopyable {
    private:
    noncopyable(noncopyable const&);
    noncopyable & operator=(noncopyable const&);
};

class my_noncopyable_type : noncopyable {
    // ...
};

Parce que nous ne voulons pas que l'utilisateur ait un pointeur de type noncopyable* à notre objet, nous dérivons en privé. Cela compte non seulement pour les non copiables, mais aussi pour de nombreuses autres classes de ce type (les politiques étant les plus courantes).

40

Modèles d'héritage public IS-A.
Modèles d'héritage non publics EST-MISE EN ŒUVRE-EN-TERMES-DE.
Modèles de confinement HAS-A, ce qui équivaut à IS-IMPLEMENTED-IN-TERM-OF.

Sutter sur le sujet . Il explique quand vous choisissez l'héritage non public plutôt que le confinement pour les détails d'implémentation.

15
Greg Rogers

L'héritage privé est principalement utilisé pour une mauvaise raison. Les gens l'utilisent pour IS-IMPLEMENTED-IN-TERM-OF, comme indiqué dans une réponse précédente, mais d'après mon expérience, il est toujours plus propre de conserver une copie plutôt que d'hériter de la classe. Une autre réponse antérieure, celle sur CBigArray, fournit un exemple parfait de cet anti-modèle.

Je me rends compte qu'il peut y avoir des cas où has-a ne fonctionne pas en raison d'une utilisation trop zélée de "protected", mais il vaut mieux réparer la classe cassée que casser une nouvelle classe.

3
Arkadiy

Par exemple, lorsque vous souhaitez réutiliser l'implémentation, mais pas l'interface d'une classe ET remplacer ses fonctions virtuelles.

3
Nemanja Trifunovic

J'ai utilisé l'héritage privé et protégé à un moment ou à un autre.

L'héritage privé est utile lorsque vous voulez que quelque chose ait le comportement de la classe de base et que vous puissiez ensuite remplacer cette fonctionnalité, mais vous ne voulez pas que le monde entier en soit conscient et l'utilise. Vous pouvez toujours utiliser l'interface d'une classe dérivée en privé en ayant une fonction renvoyant cette interface. Il est également utile lorsque vous pouvez vous enregistrer pour écouter les rappels car ils peuvent s'enregistrer à l'aide de l'interface privée.

L'héritage protégé est particulièrement utile lorsque vous avez une classe de base qui dérive des fonctionnalités utiles d'une autre classe, mais que vous souhaitez uniquement que ses classes dérivées puissent l'utiliser.

0
Daemin