Introduction
The relationship among classes is one of the fundamental activities of software design. There are two ways to relate classes: inheritance and composition.
Inheritance
Inheritance enables us to create a new class that reuses and extends behavior from another class called a base class or superclass and the newly created class is called the derived class. When we inherit a class from any other class, the derived class implicitly gains all the members of the base class except the constructors and destructor. So, the derived class can reuse a base class method and property without re-implementing it. In other words we can say, using inheritance, a derived class extends the base class functionality. The main advantage of inheritance is the reusability of the code. The other main advantages of class inheritance are, it makes it easy to modify the current implementation of the base class by just overriding an operation within the derived class. The limitation with inheritance is, we cannot change the implementation of the base class at run time.
Inheritance is a hierarchical relationship between classes. Inheritance can denote a "is - a" relationship between classes.
Inheritance is sometimes said to provide "weak encapsulation," because if you have code that directly uses a derived class then that code can be broken by changes to a base class.
An inheritance relationship between base classes and derived classes is often said to be fragile, because small changes done in the base class can ripple out and might require changes in many places within an application.
Example of Inheritance
public class BaseClass
{
public string property { get; set; }
public void BaseMethod()
{
// Do something....
}
}
public class DerivedClass : BaseClass
{
public string DerivedclassProperty { get; set; }
public void DerivedMethod()
{
// Do something....
base.BaseMethod();
}
}

In this example DerivedClass is related to the BaseClass by inheritance, here BaseClass is a superclass and DerivedClass is the subclass.
Composition
Composition is the most commonly used relation in a class diagram. In general terms, composition allows a class to contain an object instance of another class. Composition can be denoted as being an "as a part" or a "has a" relationship between classes.
In the composition approach, the derived class becomes the front-end class and the base class becomes the back-end class. The composition approach provides stronger encapsulation than inheritance, because a change to a back-end class does not necessarily break any code that relies on the front-end class. The main advantages of composition is, with carefully designed interfaces we can change references of back end classes at runtime.
Example of composition
public class FirstClass
{
public string property { get; set; }
public void FirstMethod()
{
// Do something....
}
}
public class SecondClass
{
private FirstClass firstClass = new FirstClass();
public string ClassProperty { get; set; }
public void MyMethod()
{
// Do something....
firstClass.FirstMethod();
}
}

Apurv KumarPosted Jan 10, 2021, 8:33 PM
For proper de-coupling and dependency injection, shouldn't we be using Aggregation instead of Composition...? BTW, thanks for such a legible comparison....!! :)