I was explaining OOP to my friend. I was unable to answer this question. (How shameful of me? :( )
I just escaped by saying, since OOP depicts the real world. In rea
References are store on stack while objects are store on heap. We can assign child object to parent type reference because child is type of parent and child object has reference for parent class. While parent is not of type child. Parent object doesn’t have reference to child so child reference can’t point to parent object.
I would say your example is flawed in that Child
extends from Parent
, which doesn't really follow the "is-a" relationship particularly well. Far better to have a relationship whereby both Child
and Parent
inherit from a single base class: Person
.
Using that approach it would be easier to explain to your friend why:
Person p = new Child();
... is valid, but the following is not:
// We do *not know* that the person being referenced is a Child.
Child c = person;
It is precisely this reason why this assignment is disallowed in Java: What would the additional child fields be initialised with in this case?
If it was valid, what would you expect when you read aChild.prop3
? It is not defined on aParent
.
Think "inheritance" = "specialisation", although this seems counter-intuitive at first. The set of "Childs" is a subset of the set of "Parents" (you see that your example is a bit misleading). It naturally follows that a variable that can 'hold' a "Child" cannot a hold an abitrary member of the "Parent" set because it may not be in it the "Child" subset. On the other way, a variable that can 'hold' a "Parent" can hold every member of the "Child" set.
There seems to be 2 ways of viewing inheritance. On the programming level, "Child" is a superset of "Parent" abilities, as Kornel said. But conceptually, "Child" is a specialisation of "Parent" thus representing only a subset of all possible "Parent". Think for example "Vehicle" and "Car": a Car is a special Vehicle. The set of all Cars is still a subset of all vehicles. You may even "do more" with a Car than with a general Vehicle (e.g. changing tires, fill in gasoline etc.) but it's still a Vehicle.
The assignments you are performing are called downcasting and upcasting. Downcasting is what happens when you cast an object
to a String
. Upcasting is the opposite where you are casting a type to a more general type. Upcasting never fails. Downcasting is only valid up until the point where you are downcasting to a type more specific than what the object was instantiated as.
class Named
{
public string FullName
}
class Person: Named
{
public bool IsAlive
}
class Parent: Person
{
public Collection<Child> Children
}
class Child : Person
{
public Parent parent;
}
public static void Main()
{
Named personAsNamed = new Person(); //upcast
Person person = personAsNamed ; //downcast
Child person = personAsNamed ; //failed downcast because object was instantiated
//as a Person, and child is more specialized than(is a derived type of) Person
//The Person has no implementation or data required to support the additional Child
//operations.
}
Semantically, inheritance denotes an “is a” relationship. For example, a bear “is a” kind of mammal, a house “is a” kind of tangible asset, and a quick sort “is a” particular kind of sorting algorithm. Inheritance thus implies a generalization/ specialization hierarchy, wherein a subclass specializes the more general structure or behavior of its superclasses. Indeed, this is the litmus test for inheritance: If B is not a kind of A, then B should not inherit from A. In your case it means, that Parent "is a" child, but not vice versa.
P.S. I think in this case you violates main inheritance principles.