This blog post is continuation of series of posts on understanding classes in PowerShell. Part 04 of series can be read at here.
What is Inheritance
In many classes that you create, you will find that you often need the same properties and methods from another class that you created earlier. For example, if you have a base class called the Person class, and it contains LastName and FirstName properties and a Print method, you will find that for an Employee class, you need the same properties and methods. You may also need additional properties, such as EmployeeID and Salary. When you inherit from the Person class (the base class) you can add these properties to this new Employee class, and still have access to all of the properties in the Person class. Inheritance is about the ability for one class to define itself as having all the properties and methods of a particular class, and then extending the definition of the base class by adding additional properties and methods.
Why should we use Inheritance
Inheritance is desirable because you want to avoid writing the same code over and over again. If you have two separate classes, and each one has to implement a FirstName and LastName property, you are going to have duplicate code. If you wish to change the implementation of one of these properties, you need to find all classes that have implemented these properties to make the changes. Not only is this time-consuming, but you also increase the risk of introducing bugs in the various classes.
Point to remember
One thing to remember when you are considering using inheritance is that the relationship between the two classes should be an “is a” type of relationship. For example, an Employee is a Person, and a Manager is a Person, so these two classes can inherit from the Person class. But you should not have a Leg class inherit from a Person class as a Leg is not a person.
Another thing to remember is that all PowerShell classes are subclasses of the System.Object class. So, they inherit the inheritable methods of the System.Object class.
Define inheritance in PowerShell classes
A new class that is created by inheritance is sometimes called a child class or a subclass. The class you originally inherited from is called the base class, parent class, or the superclass. The syntax for defining child class is like:
class child class name : parent class name { #some code here }
for example:
Class book { [String]$Category book(){} } Class history : book { [String]$HistoryPeriod }
Here, we have defined a parent class book and a child class history. Now, when we declare a object of the class history, we would also be able to access the members of the parent class:
PS C:\> $newbook = [history]::new() PS C:\> $newbook.Category PS C:\> $newbook.Category = "history"
We can also get the base type of a child class using [childclassname] syntax. for example:
PS C:\Windows\system32> [history] IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False history book PS C:\Windows\system32> [book] IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False book System.Object
As you can see, the parent class for book is system.object as mentioned earlier. And, when you create an instance of the book class and pass it to Get-Member, you can see that there are four methods of the book class that you didn’t define. These methods are inherited from the System.Object base class:
PS C:\Windows\system32> $newbook = New-Object -TypeName book PS C:\Windows\system32> $newbook | Get-Member
TypeName: book Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() Category Property string Category {get;set;}
So you can derive what the members of the object for history class would look like:
PS C:\Windows\system32> $newbook2 = New-Object -TypeName history PS C:\Windows\system32> $newbook2 | Get-Member TypeName: history Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() Category Property string Category {get;set;} Type Property string Type {get;set;}
Overrloading methods of Base class
You can have members that have the same name as a member in the base class, but take different parameters. This is called an overloaded method. In a subclass, it works the same way that it would if you had a method defined twice in the same class and it is called overload method.
For example, consider below code:
Class book { [String]$Category [String]$LastCheckedDate book(){} SetLastCheckedDate(){ $this.LastCheckedDate = [DateTime]::Today } } Class history : book { [String]$HistoryPeriod [String]$LastCheckedDate history(){} [String] GetLastCheckedDate(){ if($this.LastCheckedDate -lt $([DateTime]::Today)){ return $this.LastCheckedDate } else{ return ([DateTime]::Today) } } SetLastCheckedDate([DateTime]$Date){ $this.LastCheckedDate = $Date } }
Here, we have same method SetLastCheckedDate() defined in the base class book and child class history. Now, Let’s go ahead and declare an object of child class say $newbook:
$newbook = New-Object -TypeName history
If we pipe $newbook to Get-Member and specify the SetLastCheckedDate method, it tells us that it has two overloads. It doesn’t mention (and doesn’t really care) which one is defined locally and which one is inherited:
$newbook | Get-Member -MemberType Method -Name SetLastCheckedDate TypeName: history Name MemberType Definition ---- ---------- ---------- SetLastCheckedDate Method void SetLastCheckedDate(datetime Date), void SetLastCheckedDate()
If we call the SetLastChekedDate methods, they works exactly as they would if both methods were defined in the same class. Depending upon number of values passed, the appropriate method is called.
Overriding methods of Base Class
To hide a method in the base class, one can write a method that has the same arguments as the method in the parent class. That’s called overriding a method. When methods have the same name and take arguments of the same type, the method in the child class takes precedence, hides, or overrides the method in the parent class. You can do the same thing with Properties.
For example, consider below code:
Class book { [String]$Category [String]$LastCheckedDate book(){} [Void] SetLastCheckedDate([DateTime]$Date){ $this.LastCheckedDate = $Date } } Class history : book { [String]$HistoryPeriod [String]$LastCheckedDate history(){} [String] GetLastCheckedDate(){ if($this.LastCheckedDate -lt $([DateTime]::Today)){ return $this.LastCheckedDate } else{ return ([DateTime]::Today) } } [DateTime] SetLastCheckedDate([DateTime]$Date){ $this.LastCheckedDate = $Date return $this.LastCheckedDate } }
Note that we have changed the return type of method for us to cleverly identify the method being called upon. This is not necessary and is just for this example. Now, just like above, let’s go ahead and declare an object of child class say $newbook:
$newbook = New-Object -TypeName history
If we pipe $newbook to Get-Member and specify the SetLastCheckedDate method, it would show only one method associated with it:
$newbook | Get-Member -MemberType Method -Name SetLastCheckedDate TypeName: history Name MemberType Definition ---- ---------- ---------- SetLastCheckedDate Method datetime SetLastCheckedDate(datetime Date)
Since the return type is datetime object, we know that it is referring to the method defined in the child class.
Calling base class members anyhow
Even when a base class member is hidden by a subclass member, you can still call the base class member on an instance of the subclass by using syntax:
([baseClass]$instance).member
Essentially, you cast the object to the base class, enclose the casted object in parentheses to make sure it’s evaluated first, and then call the member in the usual way.
For our case, we can call the SetLastCheckedDate of the parent class book like this:
([Book]$newbook).SetLastCheckedDate("3/13/2017")
This will continue further in another blog post.
[…] blog post is continuation of series of posts on understanding classes in PowerShell. Part 05 of series can be read at here. In previous blog post, we have learned about meaning of inheritance, define child class and parent […]
LikeLike