Domanda

In C ++, non riesco a pensare a un caso in cui vorrei ereditare il privato/protetto da una classe base:

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

È davvero utile?

È stato utile?

Soluzione

E 'utile quando si desidera avere accesso ad alcuni membri della classe base, ma senza esporli nella vostra interfaccia di classe. ereditarietà privata può anche essere visto come una sorta di composizione: C ++ faq-lite ha pronunciato la seguente esempio per illustrare questa affermazione

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
};

Per ottenere la stessa semantica, si potrebbe anche scrivere la classe auto come segue:

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
}; 

Tuttavia, questo modo di fare ha diversi svantaggi:

  • il vostro intento è molto meno chiaro
  • può portare a abusiva ereditarietà multipla
  • si rompe l'incapsulamento della classe del motore in quanto è possibile accedere ai membri protetti
  • si è permesso di ignorare i metodi virtuali del motore, che è qualcosa che non si vuole se il vostro scopo è una composizione semplice

Altri suggerimenti

privato può essere utile in un bel paio di circostanze. Solo uno di loro sono politiche:

è di classe parziale modello di specializzazione la risposta a questo problema di progettazione? .

Un'altra occasione in cui è utile è quello di vietare la copia e l'assegnazione di:

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

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

Perché non vogliamo che l'utente ha un puntatore di tipo noncopyable* al nostro oggetto, deriviamo privatamente. Che conta non solo per noncopyable, ma molti altri tali classi troppo (politiche è il più comune).

modelli di ereditarietà pubblica è-A.
modelli di ereditarietà non pubblica è attuata-IN-TERMINI-DI.
modelli di contenimento HA-A, che equivale a IS-IMPLEMENTATO-IN-TERMINI-DI.

Sutter sul tema . Egli spiega quando ci si sceglie l'ereditarietà non pubblica più di contenimento per i dettagli di implementazione.

Per esempio, quando si desidera riutilizzare l'attuazione, ma non l'interfaccia di una classe e ignorare le sue funzioni virtuali.

eredità privato è usato soprattutto per la ragione sbagliata. La gente lo usa per IS attuate-IN-TERMINI-DI, come indicato in una precedente risposta, ma nella mia esperienza è sempre più pulito per conservare una copia piuttosto che ereditano dalla classe. Un altro precedente risposta, quella su CBigArray, offre un perfetto esempio di questo anti-modello.

Mi rendo conto che ci possono essere casi in cui ha-un non funziona a causa di uso eccesso di zelo di "protetta", ma è meglio per risolvere la classe rotta rispetto a rompere una nuova classe.

Ho usato sia ereditarietà privata e protetta in un punto o altro.

ereditarietà privata è utile quando si desidera qualcosa di avere il comportamento della classe base, e quindi in grado di sovrascrivere tale funzionalità, ma non si vuole che il mondo intero di essere a conoscenza di esso e usarlo. È comunque possibile utilizzare l'interfaccia di una classe derivata privatamente da avere una funzione di restituire tale interfaccia. E 'utile anche quando si possono avere le cose si registrano per l'ascolto di callback come possono registrarsi utilizzando l'interfaccia privata.

ereditarietà

protetta è particolarmente utile quando si dispone di una classe di base che deriva funzionalità utili da un'altra classe, ma desideri solo le sue classi derivate per essere in grado di utilizzarlo.

Una volta ho implementato queste strutture dati come classi:

  • Lista collegata
  • Array generico (astratto)
  • Array semplice (eredita da un array generico)
  • Array grande (eredita da un array generico)

L'interfaccia del big array lo avrebbe fatto sembrare un array, tuttavia, in realtà era un elenco collegato di array semplici di dimensione fissa.Quindi l'ho dichiarato così:

template <typename T>
class CBigArray : public IArray, private CLnkList {
    // ...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top