Pergunta

Eu estou tentando encapsular corretamente uma classe A, que só deve ser operado por classe B.

No entanto, quero herdar da classe B.

Ter um amigo B não funciona -. Amizade não é herdada

Qual é a forma geralmente aceite de realizar o que eu quero, ou eu estou cometendo um erro?

Para lhe dar um pouco mais de cor, classe A representa o estado de um sistema complexo. Ele só deve ser modificado por B, que são ações que podem ser aplicadas ao Estado de classe mudança de A.

Foi útil?

Solução

Eu suponho que você quer permitir que descendentes de B para acessar um diretamente? Se A e B são fortemente acoplados, você pode fazer uma definição de uma classe protegida dentro de si B, em vez de ser uma definição independente. Por exemplo.

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

Outra idéia é criar métodos protegidos em B que delegar suas ações para A. por exemplo.

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

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

Outras dicas

Parece que você pode precisar de fazer uma reformulação; sua classe A representa um Estado, mas a sua classe B representa um conjunto de ações. Há uma relação existe, mas não é um relacionamento de herança. Eu sugiro composição; você quer mais de um relacionamento HASA do que uma relação ISA, tanto quanto eu posso dizer.

Se eu entendi corretamente, você quer ter B e é derivados para ter acesso à implementação interna de classe A, sim?

Infelizmente, C ++ não tem o conceito de níveis "internas" de proteção que linguagens como posses C # e Java.

Você pode considerar o uso do implementação privada paradigma (pimpl) - também conhecido como ponteiros opacos , para expor a funcionalidade dentro do seu sistema usando os níveis de acesso público, que os consumidores de a e B não iria ver.

Manter tudo como está, a melhor coisa a fazer é adicionar métodos protegidos para B que dão acesso ao recurso equivalente a A seria necessário. Isso abre o encapsulamento para subclasses apenas de B.

A maneira mais simples de fazer isso é simplesmente ter B contêm um A:

classe B { protegido: Um a_; };

Em seguida, você pode escrever uma classe C que herda de B e é capaz de manipular A. Se C não deve ser capaz de fazer coisas arbitrárias para o A, em seguida, fazer o Um privado em B e fornecer métodos protegidos em B que C pode usar para fazer coisas aprovados para o a, assim:

classe B { privado: Um a_; protegido: doSomethingToA vazio (); };

A contenção é o caminho a percorrer (classe B contém membro particular do tipo A) a menos que B precisa substituir algumas virtuals em A, caso em que herança private é a coisa mais próxima.

Eu não posso ver por que você gostaria de herdar. Faça tudo em Um amigo particular e B. B, em seguida, tem um membro de que ele pode manipular livremente.

A forma como você descrever este soa mais como composição em vez de herança. Por exemplo.

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

Trabalho com os bits de informação que você deu:

Classe B deve ser responsável por preservar as invariantes de classe A e classe B deve ser a única forma de manipular A. Qualquer cliente - classe ou chamador derivados -. Não precisa saber que um existe

(Do projeto POV, há ainda nenhuma necessidade para A existir, mas eu encontrei razões práticas suficientes para tal separação que não vou segurá-la contra você;))

Isso pode exigir um monte de código clichê para ser escrito, ou alguns truques com a interface. por exemplo. se o cliente devem ser autorizados a classe de uso de à consulta de informações, mas não para modificá-lo, B poderia entregar um const & o A. agregada com um compilador de suporte __declspec (propriedade) ou similar, a dor sintática pode ser facilitado.

Se você quer ter certeza de que somente B opera em A, tornar a instância de um privado e expor uma interface protegida de B para os seus descendentes.

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

class B
{
  private:
    A a;

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

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

Pelo que eu entendo a sua pergunta, você vai precisar de algum polimorfismo . Você precisa de um abstract classe A e classe classe herda B A. Além disso, o protegido palavra-chave permite que as classes que herdam de ter acesso a certas informações e, ao mesmo tempo negar o acesso a qualquer outra coisa. Aqui está um pequeno exemplo:

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

código retirado cplusplus.com (contém informações sobre classes de polimorfismo e abstratas também).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top