Middle
In what situations is inheritance in object-oriented programming useful, and in which cases should it be avoided?
sobes.tech AI
Answer from AI
Inheritance is useful for:
- Code reuse: Common functionality is extracted into a base class.
- Creating type hierarchies (is-a relationship): When a derived class is a kind of the base class.
- Polymorphism: The ability to treat objects of different types through a common interface of the base class.
- Extending functionality: Adding new methods or fields to an existing class.
Inheritance should be avoided when:
- Liskov substitution principle is violated: A derived class cannot fully replace the base class without affecting program correctness.
- Tight coupling between classes: Changes in the base class may undesirably affect all derived classes.
- Combining functionalities from unrelated sources (has-a relationship): Composition is preferable.
- Excessive hierarchy complexity: Deep inheritance chains are hard to maintain and understand.
- Inheritance for code reuse when functionality is not a common "type": Use utility classes or delegation instead.
// Example where inheritance is useful
open class Animal {
open fun makeSound() {
println("Generic animal sound")
}
}
class Dog : Animal() { // Dog IS-A Animal
override fun makeSound() {
println("Woof")
}
}
class Cat : Animal() { // Cat IS-A Animal
override fun makeSound() {
println("Meow")
}
}
// Example where composition is preferable over inheritance for "has-a" relationship
class Engine {
fun start() { println("Engine started") }
}
// Instead of inheriting from Engine for Car
// class Car : Engine() // Bad design, Car IS-NOT an Engine
class Car {
private val engine = Engine() // Car HAS-A Engine
fun drive() {
engine.start()
println("Car driving")
}
}