Bueno, una clase abstracta puede especificar alguna implementación, pero por lo general no todo. (Dicho esto, es perfectamente posible proporcionar una clase abstracta sin miembros abstractos, pero muchos virtuales con implementaciones "no operativas"). Una interfaz proporciona la implementación no, simplemente un contrato.
Sin duda podría argumentar que si se permitiera la herencia múltiple de clases, las interfaces serían en gran parte inútiles.
Personalmente no me cuelgo de toda la distinción "is-a" versus "can-do" para la herencia. Nunca me da una intuición tan buena sobre qué hacer como simplemente jugar con diferentes ideas y ver cuáles se sienten más flexibles. (Por otra parte, soy un tipo "favor de composición sobre herencia" ...)
EDITAR: Al igual que la forma más conveniente de refutar el tercer punto de lbushkin en su comentario ... puede anular un método abstracto con un uno no virtual (en términos de no ser capaz de anular aún más) sellándolo:
public abstract class AbstractBase
{
public abstract void Foo();
}
public class Derived : AbstractBase
{
public sealed override void Foo() {}
}
clases derivadas de Derived
no pueden anular Foo
más.
No estoy de ninguna manera sugiere quiero herencia múltiple de aplicación - pero si lo tenerlo (junto con su complejidad) a continuación, una clase abstracta que acaba contenían métodos abstractos lograría casi todo que una interfaz hace (Está el tema de la implementación explícita de la interfaz, pero eso es todo lo que puedo pensar por el momento).
"favor composición sobre herencia". Bueno, hay escenarios en los que lo opuesto es más deseable, como cualquier tipo de biblioteca GUI, donde la herencia es una bendición. En mi humilde opinión, un diseño bien pensado basado en la herencia (correcta) es más útil que un diseño basado en la composición si hay suficientes jerarquías. Pero ... la herencia es más difícil que la composición en cualquier caso (¿es eso un defecto de OOP, como lo usamos hoy?) –
"si se permitiera la herencia múltiple de clases, las interfaces serían en gran parte inútiles". Estoy en desacuerdo con esa afirmación. En primer lugar, las interfaces proporcionan un nivel de desacoplamiento que incluso las clases base puramente abstractas llenas de métodos virtuales no operativos no pueden proporcionar. Ayudan a separar las obligaciones contractuales de un tipo de las inevitables preocupaciones centradas en la implementación. En segundo lugar, dado que las interfaces no tienen miembros de datos, evitan el problema de la herencia de datos en forma de diamante. En tercer lugar, C# permite que los métodos que implementan una interfaz sean no virtuales (lo que puede ser útil) - las clases abstractas no. – LBushkin
Lo siento Jon tiene que estar en desacuerdo con usted sobre la herencia múltiple. Como alguien que ha pasado gran parte de su vida en C++, créeme, es horrible. La mayoría de los desarrolladores en C++ ahora usan herencias múltiples de la misma manera que C#/java, es decir, una clase base principal más todo lo demás como 'mix-ins' – zebrabox