2011-02-05 16 views

Respuesta

22

Hay un problema aquí: esto sería una violación directa del principio de sustitución de liskov, a saber A ¿no actuar comoB por más tiempo.

Si desea reutilizar B aplicación, la solución es simplemente para hacerlo:

class A 
{ 
public: 
    void foo() { return b.foo(); } 
    void bar() { return b.bar(); } 
    // ... 

private: 
    B b; 
}; 

No abuse de la herencia, composición de uso en lugar

+4

Simplemente tuve que escribir una clase que era 99% de otra clase, pero manejé las cosas de manera diferente y tenía 1 función, solo una función que no podría existir en SEGUNDO. – rxantos

1

Si los métodos son privadas en B, entonces permanecerán ocultos a un incluso si se utiliza la herencia pública.

5

No puede "ocultarlo" per se, pero puede hacer que sea un error de tiempo de compilación para llamarlo. Ejemplo:

struct A 
{ 
    void AMethod() {} 
}; 

class B : public A 
{ 
    void AMethod() {} //Hides A::AMethod 
}; 

int main() 
{ 
    B myB; 
    myB.AMethod(); //Error: AMethod is private 
    static_cast<A*>(&myB)->AMethod(); //Ok 
    return 0; 
} 

Ejemplos de pantalla de códigos with the error y without.

Todo lo dicho, a pesar de que esto sea posible, realmente no deberías hacerlo. Confundirás el infierno de los clientes.

EDITAR: Tenga en cuenta que también puede hacerlo con virtual functions (y with the error).

+0

No creo que haya ninguna necesidad de definir el método (privado) en heredar la clase B. La declaración será, creo, suficiente. Yo diría que el método original está "oculto", si es un error en tiempo de compilación intentar usarlo (incluso si el mensaje de error difiere del caso en que el método no existe). –

+0

@eq: Eso es correcto, no hay necesidad de definirlo a menos que el método en la clase principal sea 'virtual'. (Me puse vago y usé copiar/pegar para hacer 'B') –

0

No se puede modificar la visibilidad del método original.

Se puede crear un método en el struct A con el mismo nombre y tienen que ser método privado, pero eso no impide que el método de ser llamado cuando una instancia de estructura A está siendo referenciado por una variable de tipo B.

0

¿Por qué no lo hace Virtual en la clase base y lo anula en sus hijos? (more help)

34

Si desea ocultar funciones de B de manera selectiva, no tiene mucho sentido utilizar la herencia pública en primer lugar.
Uso herencia privada & llevar selectivamente métodos de B en el ámbito de A:

struct B{ 
    void method1(){}; 
    void method2(){}; 
}; 
struct A : private B{ 
    using B::method1; 
}; 

A a; 
a.method1(); 
a.method2(); //error method2 is not accesible 
3

Para aquellos que están sugiriendo composición .. . esta podría no ser la mejor manera posible de hacer las cosas. Tengo entendido que el Principio de Sustitución de Liskov solo establece que existe la posibilidad de que las funciones de la clase base se usen en el niño, y no necesariamente. Por ejemplo, para una clase base particular, puede tener múltiples funciones que esencialmente realizan la misma operación, pero para casos específicos diferentes. En la clase derivada es posible que desee abstraer estas funciones públicas a favor de simplificar la interfaz del usuario. Aquí es donde se puede usar la herencia privada. La herencia privada también puede ser una necesidad, si tenemos funciones protegidas en la clase base que no queremos que el usuario de la clase base llame, sin embargo, serían invaluables para la clase derivada.

En resumen, si TIENE que hacerlo, utilice la herencia privada, pero la composición es preferida en la mayoría de los casos.

8

Aparte de las formas descritas en el anterior respuestas composición, herencia privada y la herencia no privado, pero con el método heredado declaró privada-otra forma de hacerlo es explícitamente delete el método heredado:

#include <iostream> 

struct A { 
    void foo() { std::cout << "foo\n"; } 
}; 

struct B : A { 
    void foo() = delete; 
}; 

int main() { 
    B b; 
    b.foo(); // COMPILER ERROR 
} 

Aunque la llamada b.foo() produce un error de compilación, el código de cliente todavía puede llamar a la versión de la clase base al clasificarse con el identificador de clase base A:

b.A::foo(); // compiles, outputs 'foo' to console 

Esto expli el modo de eliminación de CIT funciona cuando foo es no un método virtual no eliminado en A. Según el estándar C++ 11 §10.3/16, esta eliminación explícita está mal formada cuando el método eliminado en la clase derivada anula un método virtual no eliminado de la clase base. Para obtener más información sobre esta restricción, consulte las respuestas a la pregunta SO C++11 Delete Overriden Method.

1

Existe otro enfoque.

class A{ 
    void f1(); 
    void f2(); 
    void f3(); 
} 

class BInterface{ 
    void f2(); 
    void f3(); 
} 

class B : public A, BInterface 
{ 
} 

BInterface b = new B(); 
b->f1(); //doesn't work since f1 is not declared in BInterface 
b->f2(); //should work 
b->f3(); //should work 
delete(b); 

Utilice BInterface como filtro para las clases heredadas para excluir los métodos no deseados. El principio de sustitución de Liskov no se viola en este caso, ya que un objeto de la clase BInterface no es un objeto de clase A, aunque un objeto de clase B es un objeto de clase BInterface.

Cuestiones relacionadas