Difference between revisions of "Inheritance"

From TRCCompSci - AQA Computer Science
Jump to: navigation, search
(Definition added)
(Virtual & Override Examples + Abstract Definition add examples)
Line 97: Line 97:
 
For examples on how inheritance can be used to psuedo link different object instances to a given global class (allowing different, for example, Animals to all be contained in a single array despite being different types) view the examples on [[The Downsides of Arrays|Arrays]] at http://compsci.duckdns.org/mediawiki/index.php/Arrays.
 
For examples on how inheritance can be used to psuedo link different object instances to a given global class (allowing different, for example, Animals to all be contained in a single array despite being different types) view the examples on [[The Downsides of Arrays|Arrays]] at http://compsci.duckdns.org/mediawiki/index.php/Arrays.
  
== Virtual & Override Examples + Abstract Definition ==
+
== Virtual & Override + Abstract Definition ==
 
The propper etiquette for defining methods we want to be overriden is to mark them as virtual, and then have any child classes which may require them in a specific way to override them.
 
The propper etiquette for defining methods we want to be overriden is to mark them as virtual, and then have any child classes which may require them in a specific way to override them.
  
  
In it's simplest form, the virtual specifier marks a function as being fine as it is however if a child class you've made requires something more specific you may override it. Once a virtual method is called, the CSharp compiler will look for the first instance of said method existing with a body (namely being overriden) and runs it, starting it's search from the class instance being called all the way to the parent class (where it must be defined at least once). Counter to the virtual and override route to implementing specified inheritence you can also mark a method as abstract, meaning it's too general an attribute to be defined in a base class and must be set for each child class despite being required in every class which may inherit it (to do this, abstract methods are defined without a body to prevent the CSharp compiler executing an instance of it found in the base class); for example if an Animal class possesses a Walk method, the way a Animal walks is almost always inextricably linked to the type of animal it is and hence must be defined for each class which inherits it. You can remember the difference between virtual and abstract methods as abstract only posessing a body when inherited while virtual always has at least one body to be run regardless of where it's declared.
+
In it's simplest form, the virtual specifier marks a function as being fine as it is however if a child class you've made requires something more specific you may override it. Once a virtual method is called, the CSharp compiler will look for the first instance of said method existing with a body (namely being overriden) and runs it, starting it's search from the class instance being called all the way to the parent class (where it must be defined at least once). Counter to the virtual and override route to implementing specified inheritence you can also mark a method as abstract, meaning it's too general an attribute to be defined in a base class and must be set for each child class despite being required in every class which may inherit it (to do this, abstract methods are defined without a body to prevent the CSharp compiler executing an instance of it found in the base class); for example if an Animal class possesses a Walk method, the way a Animal walks is almost always inextricably linked to the type of animal it is and hence must be defined for each class which inherits it. You can remember the difference between virtual and abstract methods as abstract only posessing a body when inherited while virtual always has at least one body to be run regardless of where it's declared. To display this I will re-create the above Animal class as an example (in an abridged form):
 +
 
 +
<tabber>
 +
C#=
 +
<syntaxhighlight lang="csharp" line>
 +
private enum EGender {
 +
  Male, female
 +
  // Enumeration containing
 +
}; // possible gender values
 +
 
 +
class Animal {
 +
    public Animal(name, age, gender) {
 +
        this.name = name;
 +
        this.age = age;
 +
        this.gender = gender;
 +
    }
 +
 
 +
    public virtual void Walk() {
 +
        Console.WriteLine("{0} Is a {1} & is {2} Years Old",
 +
            this.name, this.gender, this.age)
 +
    }
 +
 
 +
    private int _age;
 +
    private String _name;
 +
    private EGender _gender;
 +
 
 +
    public int age { get { return _age; } set { _age = value; } }
 +
    public String name { get { return _name; } set { _name = value; } }
 +
    public EGender gender { get { return _gender; } set { _gender = value; } }
 +
}
 +
 
 +
class Eagle : Animal {
 +
  public override Walk() {
 +
      Console.WriteLine("{0} Is a {1} & is {2} {3}",
 +
            this.name, this.gender, this.age,
 +
            "Years Old & doesnt walk but instead flies")
 +
  }
 +
}
 +
 
 +
class Tiger : Animal {
 +
   
 +
}
 +
 
 +
</syntaxhighlight>
 +
</tabber>
 +
 
 +
Taking a look at the code above you can see Eagle & Tiger both inherit from Animal but only Eagle overrides the virtual Walk function and Tiger leaves the Walk function as is. Now as for what happens when instances of each class call the Walk function:
 +
# In Eagles case the overriden walk function will execute, as it is the latest definition of it in the hirearchy chain.
 +
# In Tigers case there is no overriden function and hence the CSharp compiler will travely up the hirearchy chain to the base class and run the function body found there.
 +
 
 +
To make sure however just run the code below:
 +
 
 +
<tabber>
 +
C#=
 +
<syntaxhighlight lang="csharp" line>
 +
 
 +
Tiger tiger = new Tiger("Atsushi", 17, EGender.Male); // New Instance of Tiger
 +
Eagle eagle = new Eagle("Torway", 14, EGender.Male); // New Instance of Eagle
 +
 +
tiger.Output(); // Call to base function in parent Animal
 +
// Outputs "Atsushi is a Male and is 17 Years old"
 +
//-- Note this is the function found in the base class
 +
 +
eagle.Output(); // Call to base function in parent Animal
 +
// Outputs "Torway is a Male and is 14 Years old & doesnt walk but instead flies"
 +
//-- Note this is the function defined in the child class
 +
 
 +
</syntaxhighlight>
 +
</tabber>

Revision as of 19:51, 17 December 2016

Definition

Inheritance is the process by which code applying to a given class can be functionally reused by another class with minimal effort. S.N. any Class which inherits from another class possesses an 'IS A' relationship (counter to a 'HAS A' relationship). Inheritance is best explained via abstraction, for example if we abstract a Ferret into it's many sub components, we find a Ferret 'IS A' Mamal which 'IS A' Animal. Class abstraction can have numerous degrees of seperation and allows the implementation of inheritance functionality, namely allowing any class in the inheritance chain to become a parent to a new class; for example if we add another mamal to the chain such as tiger, we can have this new class inherit all the functionality of the class Mamal and allow it to posess the exact same base to define itself as we did for Feret.

General Inheritance Example

To display the qualities &amp additional functionality available to a program which implements inheritance, we will create a short program displaying Animals.

 1 private enum EGender {
 2   Male, female
 3   // Enumeration containing
 4 }; // possible gender values
 5 
 6 class Animal {
 7     public Animal(name, age, gender) {
 8         this.name = name; 
 9         this.age = age;
10         this.gender = gender;
11     }
12 
13     public void Walk() {
14         Console.WriteLine("{0} Is a {1} & is {2} Years Old",
15             this.name, this.gender, this.age)
16     }
17 
18     private int _age;
19     private String _name;
20     private EGender _gender;
21 
22     public int age { get { return _age; } set { _age = value; } }
23     public String name { get { return _name; } set { _name = value; } }
24     public EGender gender { get { return _gender; } set { _gender = value; } }
25 }

The above Animal class can act as a parent for all Animals you may create down the line, for example:

1 class Tiger : Animal {
2     public Tiger(name, age, gender, numOfLegs) : base(name, age, gender) {
3        // S.N. the 'base' after the : calls the base constructor of the Parent Animal class
4         this.numOfLegs = numOfLegs;
5     }
6 
7     private int _numOfLegs;
8     public int numOfLegs { get { return _numOfLegs; } set { _numOfLegs = value; } }
9 }

The above Tiger class possesses all the same functions and code as the Animal class, but Builds on the Animal class by adding the instance property numOfLegs to the class and overrides the base constructor with a new constructor which calls the base constructor and then sets the new value restricted to the Tiger class (numOfLegs). The Good thing about this is that the Tiger Class can be given a new sibling by just creating a new class which also inherits from Animal, for example.

1 class Eagle : Animal {
2     public Eagle(name, age, gender, numOfWings) : base(name, age, gender) {
3        // S.N. the 'base' after the : calls the base constructor of the Parent Animal class
4         this.numOfWings = numOfWings;
5     }
6 
7     private int _numOfWings;
8     public int numOfLegs { get { return _numOfWings; } set { _numOfWings; = value; } }
9 }

Both Eagle & Tiger 'IS A' Animal, however Eagle 'IS NOT A' Tiger despite both being children of the class Animal. To make sure both Eagle & Tiger implement the functionality found in Animal, we can try to use the Output method in the parent class with instances of both children classes; for example:

1 Tiger tiger = new Tiger("Atsushi", 17, EGender.Male); // New Instance of Tiger
2 Eagle eagle = new Eagle("Torway", 14, EGender.Male); // New Instance of Eagle
3 
4 tiger.Output(); // Call to base function in parent Animal
5 // Outputs "Atsushi is a Male and is 17 Years old"
6 
7 eagle.Output(); // Call to base function in parent Animal
8 // Outputs "Torway is a Male and is 14 Years old"

For examples on how inheritance can be used to psuedo link different object instances to a given global class (allowing different, for example, Animals to all be contained in a single array despite being different types) view the examples on Arrays at http://compsci.duckdns.org/mediawiki/index.php/Arrays.

Virtual & Override + Abstract Definition

The propper etiquette for defining methods we want to be overriden is to mark them as virtual, and then have any child classes which may require them in a specific way to override them.


In it's simplest form, the virtual specifier marks a function as being fine as it is however if a child class you've made requires something more specific you may override it. Once a virtual method is called, the CSharp compiler will look for the first instance of said method existing with a body (namely being overriden) and runs it, starting it's search from the class instance being called all the way to the parent class (where it must be defined at least once). Counter to the virtual and override route to implementing specified inheritence you can also mark a method as abstract, meaning it's too general an attribute to be defined in a base class and must be set for each child class despite being required in every class which may inherit it (to do this, abstract methods are defined without a body to prevent the CSharp compiler executing an instance of it found in the base class); for example if an Animal class possesses a Walk method, the way a Animal walks is almost always inextricably linked to the type of animal it is and hence must be defined for each class which inherits it. You can remember the difference between virtual and abstract methods as abstract only posessing a body when inherited while virtual always has at least one body to be run regardless of where it's declared. To display this I will re-create the above Animal class as an example (in an abridged form):

 1 private enum EGender {
 2   Male, female
 3   // Enumeration containing
 4 }; // possible gender values
 5 
 6 class Animal {
 7     public Animal(name, age, gender) {
 8         this.name = name; 
 9         this.age = age;
10         this.gender = gender;
11     }
12 
13     public virtual void Walk() {
14         Console.WriteLine("{0} Is a {1} & is {2} Years Old",
15             this.name, this.gender, this.age)
16     }
17 
18     private int _age;
19     private String _name;
20     private EGender _gender;
21 
22     public int age { get { return _age; } set { _age = value; } }
23     public String name { get { return _name; } set { _name = value; } }
24     public EGender gender { get { return _gender; } set { _gender = value; } }
25 }
26 
27 class Eagle : Animal {
28    public override Walk() {
29        Console.WriteLine("{0} Is a {1} & is {2} {3}",
30             this.name, this.gender, this.age,
31             "Years Old & doesnt walk but instead flies")
32    }
33 }
34 
35 class Tiger : Animal {
36     
37 }

Taking a look at the code above you can see Eagle & Tiger both inherit from Animal but only Eagle overrides the virtual Walk function and Tiger leaves the Walk function as is. Now as for what happens when instances of each class call the Walk function:

  1. In Eagles case the overriden walk function will execute, as it is the latest definition of it in the hirearchy chain.
  2. In Tigers case there is no overriden function and hence the CSharp compiler will travely up the hirearchy chain to the base class and run the function body found there.

To make sure however just run the code below:

 1 Tiger tiger = new Tiger("Atsushi", 17, EGender.Male); // New Instance of Tiger
 2 Eagle eagle = new Eagle("Torway", 14, EGender.Male); // New Instance of Eagle
 3  
 4 tiger.Output(); // Call to base function in parent Animal
 5 // Outputs "Atsushi is a Male and is 17 Years old"
 6 //-- Note this is the function found in the base class
 7  
 8 eagle.Output(); // Call to base function in parent Animal
 9 // Outputs "Torway is a Male and is 14 Years old & doesnt walk but instead flies"
10 //-- Note this is the function defined in the child class