Domanda

Sto cercando di correttamente incapsulare una classe A, che dovrebbe essere utilizzato solo dalla classe B.

Tuttavia, voglio ereditare dalla classe B.

Avere Un amico che B non funziona -- amicizia non è ereditata.

Ciò che è generalmente accettato di compiere ciò che voglio, o sto facendo un errore?

Per dare un po ' di più il colore, la classe A rappresenta un complesso sistema di stato.Dovrebbe essere modificato solo da B, che sono azioni che possono essere applicati per modificare classe A dello stato di.

È stato utile?

Soluzione

Presumo che si desidera consentire discendenti di B per accedere direttamente?Se A e B sono strettamente accoppiati, si può fare Un protetto definizione di classe all'interno di B stesso, invece di essere una società indipendente di definizione.E. G.

class B
{
protected:
    class A
    {
    };
};

Un'altra idea è quella di creare metodi protetti in B che delegare le loro azioni A.E. G.

class A
{
friend class B;
private:
    void DoSomething();
};

class B
{
protected:
    void DoSomething(A& a) { a.DoSomething(); }
};

Altri suggerimenti

Suona come potrebbe essere necessario fare una riprogettazione;la classe A rappresenta lo Stato, ma la Classe B rappresenta un insieme di azioni.C'è una relazione c'è, ma non è una relazione di ereditarietà.Vorrei suggerire di composizione;si desidera più di un HASA rapporto di relazione ISA, per quanto posso dire.

Se ho capito bene, si desidera avere B e derivati per avere accesso all'interno l'implementazione della classe A, sì?

Sfortunatamente, il C++ non hanno il concetto di "interno" livelli di protezione che linguaggi come C# e Java possedere.

Si può considerare l'uso della implementazione privata paradigma (pimpl), noto anche come puntatori opachi, per esporre la funzionalità all'interno del sistema, utilizzando i mezzi pubblici livelli di accesso, che i consumatori di A e B non vedere.

Mantenere tutto come è, la cosa più semplice da fare è aggiungere i metodi protetti a B che danno l'accesso alle funzionalità equivalente di Un si avrebbe bisogno.Questo apre l'incapsulamento solo sottoclassi di B.

Il modo più semplice per fare questo è semplicemente B contiene Un:

class B { protetto:Un a_;};

Quindi, è possibile scrivere una classe C che eredita da B ed è in grado di manipolare A.Se C non dovrebbe essere in grado di fare arbitrario cose l'Una, poi di fare il bagno privato in B e fornire metodi protetti in B che in C si può utilizzare per fare approvata cose l'Una, in questo modo:

class B { privato:Un a_;protetto:void doSomethingToA();};

Il contenimento è la strada da percorrere (classe B contiene membro privato di tipo A) a meno che B deve eseguire l'override di alcuni virtuali in Un, nel qual caso l'ereditarietà privata è la cosa più vicina.

Non posso vedere il motivo per cui si desidera ereditare.Fare tutto in privato e amico B.B quindi è un membro di un che può manipolare liberamente.

Il modo di descrivere questo suona più come composizione, piuttosto che di ereditarietà.E. g.

class ComplexMachine {
  public:
    setState(int state);
};

class Operator {
   public:
   Operator(ComplexMachine & m) :_m(m) {};

   void drive() { _m->setState(1); }
   void turn() { _m->setState(2); }
   void stop() { _m->setState(0); }

   private:
   ComplexMachine _m;   
};

class SmoothOperator : public Operator { }

Lavorare con i bit di informazione che ti hanno dato:

Classe B dovrebbe essere responsabile per la conservazione delle invarianti di classe A e classe B dovrebbe essere l'unico modo per manipolare A.Qualsiasi client - classe derivata o chiamante - non dovrebbe bisogno di sapere che esiste.

(Dalla progettazione, POV, c'è anche no bisogno per esistere, ma ho incontrato abbastanza ragioni pratiche per una separazione che io non tenerlo contro di voi ;))

Questo potrebbe richiedere un sacco di codice standard per essere scritto, o qualche trucchetto con l'interfaccia.ad es.se il client dovrebbe essere consentito di utilizzare la classe di Una query di informazioni, ma non di modificarlo, B potrebbe dare un const & a aggregato A.Con un compilatore di sostegno __declspec(proprietà) o simili, sintattico dolore può essere alleviato.

Se si vuole essere sicuri che solo B opera A, rendere l'istanza di Un privato ed esporre un'interfaccia protetta da B a i suoi discendenti.

class A
{
  public:
    void foo() {}
};

class B
{
  private:
    A a;

  protected:
    void CallAFoo() { a.foo() };
};

class C : public B
{
    void goo() { CallAFoo(); }
};

Da quello che ho capito dalla tua domanda, avrete bisogno di alcuni polimorfismo.Hai bisogno di un abstract classe A e di classe B eredita la classe A.Inoltre, l' protetta parola chiave consente l'classi che ereditano per avere accesso a determinate informazioni, allo stesso tempo, di negare l'accesso a qualsiasi altra cosa.Ecco un piccolo esempio:

// dynamic allocation and polymorphism
#include <iostream>
using namespace std;

class CPolygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area (void) =0;
    void printarea (void)
      { cout << this->area() << endl; }
  };

class CRectangle: public CPolygon {
  public:
    int area (void)
      { return (width * height); }
  };

class CTriangle: public CPolygon {
  public:
    int area (void)
      { return (width * height / 2); }
  };

int main () {
  CPolygon * ppoly1 = new CRectangle;
  CPolygon * ppoly2 = new CTriangle;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  ppoly1->printarea();
  ppoly2->printarea();
  delete ppoly1;
  delete ppoly2;
  return 0;
}

Codice preso da cplusplus.com (contiene informazioni sul polimorfismo e classi astratte, troppo).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top