Pregunta

Estoy tratando de encapsular adecuadamente una clase A, que sólo debe ser operado por clase B.

Sin embargo, quiero heredar de la clase B.

Tener un amigo B no funciona -. Amistad no se hereda

¿Cuál es la forma generalmente aceptada de lograr lo que quiero, o estoy cometiendo un error?

Para darle un poco más de color, clase A representa el estado de un sistema complejo. Sólo debe ser modificado por B, que son las acciones que se pueden aplicar para cambiar el estado de una clase.

¿Fue útil?

Solución

Asumo desea permitir que los descendientes de B para acceder a una directamente? Si A y B están estrechamente unidas, se puede hacer una definición de una clase protegida dentro B en sí, en lugar de ser una definición independiente. Por ejemplo.

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

Otra idea es crear métodos protegidos en B que delegan sus acciones a A. por ejemplo.

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

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

Otros consejos

Parece que es posible que tenga que hacer un rediseño; la clase A representa un Estado, pero su Clase B representa un conjunto de acciones. Hay una relación allí, pero no es una relación de herencia. Yo sugeriría composición; quieres más de una relación HASA que una relación de ISA, por lo que yo puedo decir.

Si he entendido bien, usted quiere tener B y sus derivados para tener acceso a la aplicación interna de la clase A, sí?

Por desgracia, C ++ no tiene el concepto de niveles de protección "internos" que lenguajes como C # y Java poseen.

Puede considerar el uso de la privada (pimpl) - también conocido como puntero opaco , para exponer la funcionalidad dentro de su sistema utilizando los niveles de acceso público, que los consumidores de a y B no verían.

Mantener todo como está, la cosa más fácil que hacer es añadir métodos protegidos a B que dan acceso a la función equivalente de una necesitaría. Esto abre la encapsulación a sólo subclases de B.

La forma más sencilla de hacer esto es simplemente tener una A B contendrá:

clase B { protegido:   A a_; };

A continuación, se puede escribir una clase que hereda de C y B es capaz de manipular A. Si C no debería ser capaz de hacer cosas arbitrarias a la A, a continuación, hacer que el soldado en B y proporcionar métodos protegidos en B C que se puede utilizar para hacer las cosas aprobadas a la a, así:

clase B { privado:   A a_; protegido:   anular doSomethingToA (); };

La contención es el camino a seguir (clase B contiene miembro privado de tipo A) a no ser que B necesita para anular algunas virtuals en A, en cuyo caso herencia privada es lo más parecido.

No puedo ver por qué desea heredar. Hacer todo en un B privado y amigo B. A continuación tiene un elemento de A que se puede manipular libremente.

La forma de describir esto suena más como composición en lugar de herencia. Por ejemplo.

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

El trabajo con los bits de información que ha proporcionado:

Clase B debe ser responsable de la preservación de los invariantes de clase A y clase B debe ser la única manera de manipular A. Cualquier cliente - clase o persona que llama derivada -. No debería ser necesario saber que existe un

(De POV diseño, hay incluso sin necesidad para que A existe, pero se han encontrado con suficiente razones prácticas para una separación tal que no tomará en su contra usted;))

Esto puede requerir una gran cantidad de código repetitivo a ser escrito, o algún truco con la interfaz. p.ej. si el cliente debe ser permitido el uso de la clase A para consultar información, pero no modificarlo, B podría entregar una constante y a la A. agregada con un compilador de soporte __declspec (propiedad) o similar, el dolor se puede aliviar sintáctica.

Si usted quiere estar seguro de que sólo opera en un B, crea la instancia de un privado y exponer una interfaz protegida de B a sus descendientes.

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

class B
{
  private:
    A a;

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

class C : public B
{
    void goo() { CallAFoo(); }
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top