Basic class inheritance
Things one should read :
1 2 3 4 5 6 7 8 |
Class Base { [string]$BaseProperty = 'Base Value' #Implicit constructur Base() is here. } Class SubBase : Base{ [string]$SubBaseProperty = 'SubBase Value' #implicit constructor Base() is here, If instantiated , Base() implicit constructor is called as well } |
This is i think the basic variant of inheritance. Our child class SubBase, comes from Base class. Now what it might not seem to be clear from first insight is that there are 2 implicit constructors there. I marked that with a #comment. Now let’s have a look at a bit more complex extension.
1 2 3 4 5 6 7 8 9 10 11 12 |
Class Base { [string]$BaseProperty = 'Base Value' #implicit parameterless constructor is here. Implicit Base() is called when this is instantiated } Class SubBase : Base{ [string]$SubBaseProperty = 'SubBase Value' #Explicit parameterless constructor is here. SubBase(){ Write-Host "SubBase constructor invoked" -ForegroundColor "blue" $this.SubBaseProperty = 'SubBaseCtorInvoked' } } |
What we can see here is that in BaseClass we have still ‘none’ explicitly written constructors ( hence we get 1 implicitly ). For the child SubClass we have an explicit constructor () – parameterless. When it get called, it will call the parameterless constructor from the base class. On the screenshot you don’t see any effect of base class constructor, but that’s just because the implicit () constructor doesn’t do much. If we do it the other way around :
1 2 3 4 5 6 7 8 9 10 11 12 |
Class Base { [string]$BaseProperty = 'Base Value' #explicit parameterless constructor is here. Base(){ Write-Host "Base constructor invoked" -ForegroundColor "red" $this.BaseProperty = 'BaseCtorInvoked' } } Class SubBase : Base{ [string]$SubBaseProperty = 'SubBase Value' #implicit parameterless constructor is here. } |
You see that everything worked just fine while creating SubBase class. It used the implicit () constructor, and it called the parent () explicit constructor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# If Base class constructor is explicitly defined, it gets executed, before the same sig ctor will run from the subbase class Class Base { [string]$BaseProperty = 'Base Value' #Explicit parameterless constructor is here. Base() { Write-Host "#1 $(Get-date) Base constructor invoked" -ForegroundColor 'red' $this.BaseProperty = 'BaseCtorInvoked' } } #If SubBase constructor is explicitly defined, it gets executed, after the same sig ctor will run from the base class Class SubBase : Base{ [string]$SubBaseProperty = 'SubBase Value' #Explicit parameterless constructor is here. SubBase(){ Write-Host "#2 $(Get-Date) SubBase constructor invoked" -ForegroundColor 'blue' $this.SubBaseProperty = 'SubBaseCtorInvoked' } } |
So now, we have really written our own () constructors. I type () to state that, those have zero arguments. When we create the SubBase class child instance, we see that first a ‘red’ base class () constructor was called, and after that our SubBase ‘blue’ constructor was called. You see now that when you will invoke a constructor of signature X from child class, it will always(ALMOST), call the same signature X constructor on parent class. What i mean by signature X is a special, unique set of parameters () – parameterless, ([int]$param), ([int]$param,[string]$param2) etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
Class Base { [string]$BaseProperty = 'Base Value' #Explicit parameterless constructor is here. Base() { Write-Host "#1 $(Get-date) Base constructor invoked" -ForegroundColor 'red' $this.BaseProperty = 'BaseCtorInvoked' } } Class SubBase : Base{ [string]$SubBaseProperty = 'SubBase Value' #Explicit parameterless constructor is here. SubBase(){ Write-Host "#2 $(Get-Date) SubBase constructor invoked" -ForegroundColor 'blue' $this.SubBaseProperty = 'SubBaseCtorInvoked' } } Class TriSubBase : SubBase{ [string]$TriSubBaseProperty = 'TriSubBase Value' #Explicit parameterless constructor is here. TriSubBase(){ Write-Host "#3 $(Get-Date) TriSubBase constructor invoked" -ForegroundColor 'yellow' $this.TriSubBaseProperty = 'TriSubBaseCtorInvoked' } } |
Above is an example with 3 classes. While invoking an instance of child TriSubBase, all other parents constructors were called. Now let’s make it a bit complex.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Class Base { [string]$BaseProperty = 'Base Value' #Explicit parameterless constructor is here. Base([int]$BaseNum) { Write-Host "#1 $(Get-date) Base constructor invoked" -ForegroundColor 'red' $this.BaseProperty = 'BaseCtorInvoked'+$BaseNum } } #SubBase explicit default constructor is present. It will try to call the Base() constructor. This will fail, since there isn't any. Class SubBase : Base{ [string]$SubBaseProperty = 'SubBase Value' #Explicit parameterless constructor is here. SubBase(){ Write-Host "#2 $(Get-Date) SubBase constructor invoked" -ForegroundColor 'blue' $this.SubBaseProperty = 'SubBaseCtorInvoked' } } |
So it’s not possible in this particular situation to make an instance of our subBase class, because when we call parameterless constructor on child, a parameterless constructor on parent also wants to be executed, but this fails, since we did not put any. The moment we have created a custom non parameterless constructor, the default / implicit () constructor is not being implemented. So when we do child(), -> then parent() wants to be invoked, but this is not happening since () signature is not there. 2 solutions. Just to recap, when you will not create any constructor explicitly, your class gets the default () parameterless implicit constructor. Once you create a constructor with paramater, the implicit parameterless constructor is gone.
Class constructor base mapping
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Class Base { [string]$BaseProperty = 'Base Value' #Explicit parameterless constructor is here. Base(){} Base([int]$BaseNum) { Write-Host "#1 $(Get-date) Base constructor invoked" -ForegroundColor 'red' $this.BaseProperty = 'BaseCtorInvoked'+$BaseNum } } #SubBase explicit default constructor is present. It will try to call the Base() constructor. It will works since we just added it. Class SubBase : Base{ [string]$SubBaseProperty = 'SubBase Value' #Explicit parameterless constructor is here. SubBase(){ Write-Host "#2 $(Get-Date) SubBase constructor invoked" -ForegroundColor 'blue' $this.SubBaseProperty = 'SubBaseCtorInvoked' } } |
We quickly added a baseclass () empty constructor, and that will do. Remember i wrote “You see now that when you will invoke a constructor of signature X or child class, it will always(ALMOST) call the same signature X constructor on parent class” . So this is the almost moment 😉 We can also create a kind of a mapping for a constructor. Our parameterless constructor from child, can be mapped to a constructor with parameter on parent using the : base() keyword.(you can map it to any constructor you want)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Class Base { [string]$BaseProperty = 'Base Value' #Explicit parameterless constructor is here. Base([int]$BaseNum) { Write-Host "#1 $(Get-date) Base constructor invoked" -ForegroundColor 'red' $this.BaseProperty = 'BaseCtorInvoked'+$BaseNum } } #SubBase explicit default constructor is present. Class SubBase : Base{ [string]$SubBaseProperty = 'SubBase Value' #Explicit parameterless constructor is here that is mapped to ([int]) from Parent SubBase() : base(4){ Write-Host "#2 $(Get-Date) SubBase constructor invoked" -ForegroundColor 'blue' $this.SubBaseProperty = 'SubBaseCtorInvoked' } } |
And as last example a really cheap implementation of an interface in case one would be looking for how to implement an IComperable interface in his class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class book : System.IComparable{ [int]$Pagesinbook [string]$Author [String]$title book ([int]$pages,[string]$author,[string]$title){ $this.Pagesinbook = $pages $this.Author = $author $this.Title = $title } [int] CompareTo([object] $obj) { if ($this.Pagesinbook -lt $obj.Pagesinbook) { return -1; } elseif ($this.Pagesinbook -gt $obj.Pagesinbook) { return 1; } return 0; } } |
This creates a book class, a book as an author, title, and number of pages(pagesinbook). We will try to sort our books objects later having in mind that we will be using the pagesinbook property for doing this. Let’s make 10 randon books:
Now let’s try to sort them, and compare 2 books.
As you can see, we have successfully inherited from IComparable class, as we can sort and compare our objects.
Summary
I have not explained everything about powershell classes, as i think the sources i mentioned would do it better. I just focused on the part that was really hard for me to understand in the beginning. So in case there are more people like me, having issues with grasping the constructor inheritance, this is for you 😉