Home

Class Inheritance

 

Inheritance Fundamentals

 

Introduction

Class inheritance is one of the most important aspects of object-oriented programming (OOP). It makes it possible to use the characteristics and behaviors of an existing class, apply those feature to a new class instead of re-creating those behaviors from scratch. The new class can then simply add new functionalities on top of those of the existing class.

In class inheritance, the existing class is referred to as the parent or base class. The new class is referred to as child class and is said to derive from the base class. Normally, not every class is inherited from another class. Most classes can serve as parent but many classes cannot serve as parents. Unlike human inheritance, a child class can have only one base class. Like human inheritance, a child class can have ancestry as far as possible.

Creating Class Inheritance

Before creating inheritance, you must have a class that will serve as parent or base. You can use one of the many built-in classes available from both the F# library and the .NET Framework, or you can create your own class. Here is an example:

open System
open System.Windows.Forms

type Circle(radius) =
    let mutable rad = radius
    member this.Radius with get() = rad and set(r) = rad <- r
    member this.Diameter with get() = rad * 2.00
    member this.Circumference with get() = this.Diameter * 3.14156
    member this.Area with get() = rad * rad * 3.14156

// Form: Circle
let geometricCircle = new Form()
geometricCircle.Width  <- 285
geometricCircle.Height <- 170
geometricCircle.Text <- "Geometric Circle"

// Label: Radius
let lblRadius = new Label()
lblRadius.Left  <- 18
lblRadius.Top   <- 19
lblRadius.Width <- 80
lblRadius.Text  <- "Radius:"
geometricCircle.Controls.Add lblRadius

// Text Box: Radius
let txtRadius = new TextBox()
txtRadius.Left  <- 105
txtRadius.Top   <- 16
txtRadius.Width <- 74
txtRadius.Text  <- "0.00"
geometricCircle.Controls.Add txtRadius

// Button: Calculate
let btnCalculate = new Button()
btnCalculate.Left <- 186
btnCalculate.Top  <-  16
btnCalculate.Text <- "Calculate"

// Label: Diameter
let lblDiameter = new Label()
lblDiameter.Left  <- 18
lblDiameter.Top   <- 53
lblDiameter.Width <- 80
lblDiameter.Text  <- "Diameter:"
geometricCircle.Controls.Add lblDiameter

// Text Box: Diameter
let txtDiameter = new TextBox()
txtDiameter.Left  <- 105
txtDiameter.Top   <- 50
txtDiameter.Width <- 74
geometricCircle.Controls.Add txtDiameter

// Label: Circumference
let lblCircumference = new Label()
lblCircumference.Left  <- 18
lblCircumference.Top   <- 82
lblCircumference.Width <- 80
lblCircumference.Text  <- "Circumference:"
geometricCircle.Controls.Add lblCircumference

// Text Box: Circumference
let txtCircumference = new TextBox()
txtCircumference.Left  <- 105
txtCircumference.Top   <- 80
txtCircumference.Width <- 74
geometricCircle.Controls.Add txtCircumference

// Label: Area
let lblArea = new Label()
lblArea.Left  <-  18
lblArea.Top   <- 110
lblArea.Width <-  80
lblArea.Text  <- "Area:"
geometricCircle.Controls.Add lblArea

// Text Box: Area
let txtArea = new TextBox()
txtArea.Left  <- 105
txtArea.Top   <- 110
txtArea.Width <- 74
geometricCircle.Controls.Add txtArea

// Button: Close
let btnClose = new Button()
btnClose.Left  <- 186
btnClose.Top   <- 108
btnClose.Text <- "Close"

let btnCloseClick _ = geometricCircle.Close()
btnClose.Click.Add btnCloseClick
geometricCircle.Controls.Add btnClose

let btnCalculateClick e =
    let radius = float txtRadius.Text
    let plate  = new Circle(radius)

    let strDiameter      = sprintf "%f" plate.Diameter
    let strCircumference = sprintf "%f" plate.Circumference
    let strArea          = sprintf "%f" plate.Area

    txtDiameter.Text      <- strDiameter
    txtCircumference.Text <- strCircumference
    txtArea.Text          <- strArea

btnCalculate.Click.Add btnCalculateClick
    
geometricCircle.Controls.Add btnCalculate

Application.Run geometricCircle

Here is an example of executing the program:

Introduction to Inheritance

To create class inheritance based on an existing class, you use the inherit keyword. The primary formula to follow is:

type NewClassName =
    inherit BaseClassName
	body

Inheritance and the Primary Constructor

The formula to inherit using the primary constructor of the base class is:

type NewClassName(Parameter(s)) =
    inherit ParentClassName(Parameter(s))
	body

Start with the type keyword followed by a name for the new class. The name of the new class can (should) be followed by parentheses. As mentioned in our introduction, the primary purpose of a derived class is to add to the characteristics of an existing class. As a result, the constructor of the child class likely takes more parameters than the constructor of the parent (but this is not a requirement; it is simply more likely). Here is an example:

type Circle(radius) =
    let mutable rad = radius
    member this.Radius with get() = rad and set(r) = rad <- r
    member this.Diameter with get() = rad * 2.00
    member this.Circumference with get() = this.Diameter * 3.14156
    member this.Area with get() = rad * rad * 3.14156
    
type Cylinder(radius, height) =
    inherit Circle(radius)
	. . .

If the constructor of the child class takes more parameters than the constructor of the parent class, in the body of the derived class, you should (must) what to do with the extra parameter(s). For example, you can create a property for it(them). Here is an example:

type Circle(radius) =
    let mutable rad = radius
    member this.Radius with get() = rad and set(r) = rad <- r
    member this.Diameter with get() = rad * 2.00
    member this.Circumference with get() = this.Diameter * 3.14156
    member this.Area with get() = rad * rad * 3.14156

type Cylinder(radius, height) =
    inherit Circle(radius)
    let mutable hgt = height
    member this.Height with get() = hgt and set(h) = hgt <- h

Outside of the classes, an object created from the child class has access to the properties and methods of the parent class. Here are examples:

open System
open System.Windows.Forms

type Circle(radius) =
    let mutable rad = radius
    member this.Radius with get() = rad and set(r) = rad <- r
    member this.Diameter with get() = rad * 2.00
    member this.Circumference with get() = this.Diameter * 3.14156
    member this.Area with get() = rad * rad * 3.14156

type Cylinder(radius, height) =
    inherit Circle(radius)
    let mutable hgt = height
    member this.Height with get() = hgt and set(h) = hgt <- h

// Form: Cylinder
let geometricCircle = new Form()
geometricCircle.Width  <- 315
geometricCircle.Height <- 210
geometricCircle.Text <- "Geometric Cylinder"

// Label: Radius
let lblRadius = new Label()
lblRadius.Left  <- 18
lblRadius.Top   <- 19
lblRadius.Width <- 80
lblRadius.Text  <- "Radius:"
geometricCircle.Controls.Add lblRadius

// Text Box: Radius
let txtRadius = new TextBox()
txtRadius.Left  <- 135
txtRadius.Top   <- 16
txtRadius.Width <- 74
txtRadius.Text  <- "0.00"
geometricCircle.Controls.Add txtRadius

// Label: Height
let lblHeight = new Label()
lblHeight.Left  <- 18
lblHeight.Top   <- 53
lblHeight.Width <- 80
lblHeight.Text  <- "Height:"
geometricCircle.Controls.Add lblHeight

// Text Box: Height
let txtHeight = new TextBox()
txtHeight.Left  <- 135
txtHeight.Top   <- 50
txtHeight.Width <- 74
txtHeight.Text  <- "0.00"
geometricCircle.Controls.Add txtHeight

// Button: Calculate
let btnCalculate = new Button()
btnCalculate.Left <- 216
btnCalculate.Top  <-  49
btnCalculate.Text <- "Calculate"

// Label: Base Diameter
let lblBaseDiameter = new Label()
lblBaseDiameter.Left  <- 18
lblBaseDiameter.Top   <- 82
lblBaseDiameter.Width <- 110
lblBaseDiameter.Text  <- "Base Diameter:"
geometricCircle.Controls.Add lblBaseDiameter

// Text Box: Base Diameter
let txtBaseDiameter = new TextBox()
txtBaseDiameter.Left  <- 135
txtBaseDiameter.Top   <- 80
txtBaseDiameter.Width <- 74
txtBaseDiameter.Text  <- "0.00"
geometricCircle.Controls.Add txtBaseDiameter

// Label: Base Circumference
let lblBaseCircumference = new Label()
lblBaseCircumference.Left  <- 18
lblBaseCircumference.Top   <- 112
lblBaseCircumference.Width <- 110
lblBaseCircumference.Text  <- "Base Circumference:"
geometricCircle.Controls.Add lblBaseCircumference

// Text Box: Base Circumference
let txtBaseCircumference = new TextBox()
txtBaseCircumference.Left  <- 135
txtBaseCircumference.Top   <- 110
txtBaseCircumference.Width <-  74
txtBaseCircumference.Text  <- "0.00"
geometricCircle.Controls.Add txtBaseCircumference

// Label: Base Area
let lblBaseArea = new Label()
lblBaseArea.Left  <-  18
lblBaseArea.Top   <- 142
lblBaseArea.Width <-  80
lblBaseArea.Text  <- "Base Area:"
geometricCircle.Controls.Add lblBaseArea

// Text Box: Area
let txtBaseArea = new TextBox()
txtBaseArea.Left  <- 135
txtBaseArea.Top   <- 140
txtBaseArea.Width <- 74
txtBaseArea.Text  <- "0.00"
geometricCircle.Controls.Add txtBaseArea

// Button: Close
let btnClose = new Button()
btnClose.Left  <- 216
btnClose.Top   <- 139
btnClose.Text <- "Close"

let btnCloseClick _ = geometricCircle.Close()
btnClose.Click.Add btnCloseClick
geometricCircle.Controls.Add btnClose

let btnCalculateClick e =
    let radius = float txtRadius.Text
    let height = float txtHeight.Text
    let pipe  = new Cylinder(radius, height)

    let strDiameter      = sprintf "%f" pipe.Diameter
    let strCircumference = sprintf "%f" pipe.Circumference
    let strArea          = sprintf "%f" pipe.Area

    txtBaseDiameter.Text      <- strDiameter
    txtBaseCircumference.Text <- strCircumference
    txtBaseArea.Text          <- strArea

btnCalculate.Click.Add btnCalculateClick
    
geometricCircle.Controls.Add btnCalculate

Application.Run geometricCircle  

Here is an example of executing the program:

Inheritance and the Primary Constructor

If the primary constructor of the child class is taking fewer parameters than the primary constructor of the parent class, make sure you indicate what the child class should do about the extra parameter(s).

     

Accessing the Base Class

To give you access to the members of the parent class from the child class, the F# language provides the base keyword. To use it, type base followed by a period and the parent member you want to access. Members declared with the let keyword in the parent class are not accessible in the child class. Here are examples:

open System
open System.Windows.Forms

type Circle(radius) =
    let mutable rad = radius
    member this.Radius with get() = rad and set(r) = rad <- r
    member this.Diameter with get() = rad * 2.00
    member this.Circumference with get() = this.Diameter * 3.14156
    member this.Area with get() = rad * rad * 3.14156

type Cylinder(radius, height) =
    inherit Circle(radius)
    let mutable hgt = height
    member this.Height with get() = hgt and set(h) = hgt <- h
    member this.LateralArea with get() = base.Radius * hgt * 2.00 * 3.14156
    member this.TotalArea = base.Area + this.LateralArea
    member this.Volume with get() = base.Radius * base.Radius * hgt * 3.14156

// Form: Cylinder
let geometricCircle = new Form()
geometricCircle.Width  <- 315
geometricCircle.Height <- 210
geometricCircle.Text <- "Geometric Cylinder"

// Label: Radius
let lblRadius = new Label()
lblRadius.Left  <- 18
lblRadius.Top   <- 19
lblRadius.Width <- 80
lblRadius.Text  <- "Radius:"
geometricCircle.Controls.Add lblRadius

// Text Box: Radius
let txtRadius = new TextBox()
txtRadius.Left  <- 135
txtRadius.Top   <- 16
txtRadius.Width <- 74
txtRadius.Text  <- "0.00"
geometricCircle.Controls.Add txtRadius

// Label: Height
let lblHeight = new Label()
lblHeight.Left  <- 18
lblHeight.Top   <- 53
lblHeight.Width <- 80
lblHeight.Text  <- "Height:"
geometricCircle.Controls.Add lblHeight

// Text Box: Height
let txtHeight = new TextBox()
txtHeight.Left  <- 135
txtHeight.Top   <- 50
txtHeight.Width <- 74
txtHeight.Text  <- "0.00"
geometricCircle.Controls.Add txtHeight

// Button: Calculate
let btnCalculate = new Button()
btnCalculate.Left <- 216
btnCalculate.Top  <-  49
btnCalculate.Text <- "Calculate"

// Label: Base Diameter
let lblBaseDiameter = new Label()
lblBaseDiameter.Left  <- 18
lblBaseDiameter.Top   <- 82
lblBaseDiameter.Width <- 110
lblBaseDiameter.Text  <- "Base Diameter:"
geometricCircle.Controls.Add lblBaseDiameter

// Text Box: Base Diameter
let txtBaseDiameter = new TextBox()
txtBaseDiameter.Left  <- 135
txtBaseDiameter.Top   <- 80
txtBaseDiameter.Width <- 74
txtBaseDiameter.Text  <- "0.00"
geometricCircle.Controls.Add txtBaseDiameter

// Label: Base Circumference
let lblBaseCircumference = new Label()
lblBaseCircumference.Left  <- 18
lblBaseCircumference.Top   <- 112
lblBaseCircumference.Width <- 110
lblBaseCircumference.Text  <- "Base Circumference:"
geometricCircle.Controls.Add lblBaseCircumference

// Text Box: Base Circumference
let txtBaseCircumference = new TextBox()
txtBaseCircumference.Left  <- 135
txtBaseCircumference.Top   <- 110
txtBaseCircumference.Width <-  74
txtBaseCircumference.Text  <- "0.00"
geometricCircle.Controls.Add txtBaseCircumference

// Label: Base Area
let lblBaseArea = new Label()
lblBaseArea.Left  <-  18
lblBaseArea.Top   <- 142
lblBaseArea.Width <-  80
lblBaseArea.Text  <- "Base Area:"
geometricCircle.Controls.Add lblBaseArea

// Text Box: Area
let txtBaseArea = new TextBox()
txtBaseArea.Left  <- 135
txtBaseArea.Top   <- 140
txtBaseArea.Width <- 74
txtBaseArea.Text  <- "0.00"
geometricCircle.Controls.Add txtBaseArea

// Button: Close
let btnClose = new Button()
btnClose.Left  <- 216
btnClose.Top   <- 139
btnClose.Text <- "Close"

let btnCloseClick _ = geometricCircle.Close()
btnClose.Click.Add btnCloseClick
geometricCircle.Controls.Add btnClose

let btnCalculateClick e =
    let radius = float txtRadius.Text
    let height = float txtHeight.Text
    let pipe  = new Cylinder(radius, height)

    let strDiameter      = sprintf "%f" pipe.Diameter
    let strCircumference = sprintf "%f" pipe.Circumference
    let strArea          = sprintf "%f" pipe.Area

    txtBaseDiameter.Text      <- strDiameter
    txtBaseCircumference.Text <- strCircumference
    txtBaseArea.Text          <- strArea

btnCalculate.Click.Add btnCalculateClick
    
geometricCircle.Controls.Add btnCalculate

Application.Run geometricCircle

Here is an example of executing the program:

Accessing the Base Class

Transitive Inheritance

Just as a child class can inherit from a parent class, another class can inherit from the child class, making such a new class a grand-child of the first parent class. When a class C inherits from a class B that itself inherits from a class A, class C inherits (public) members from both class B (its own parent) and from class A (its grand-parent). Here is an example:

type Square(length) =
    let mutable len = length
    member this.Length with get() = len and set(value) = len <- value
    member this.Perimeter with get() = len * 4.00
    member this.Area with get() = len * len

type Rectangle(length, width) =
    inherit Square(length)
    let mutable wide = width
    member this.Width with get() = wide and set(value) = wide <- value
    member this.Perimeter with get() = (base.Length + wide) * 2.00
    member this.Area with get() = base.Length * wide

type RectangularPrism(length, width, height) =
    inherit Rectangle(length, width)
    let mutable hgt = height
    member this.Height with get() = hgt and set(h) = hgt <- h
    member this.Area = ((base.Length * base.Width) + (base.Length * hgt) + (base.Width * hgt)) * 2.00
    member this.Volume with get() = base.Length * base.Width * hgt

let card = new Square(24.58)
let flag = new Rectangle(24.58, 18.74)
let box  = new RectangularPrism(24.58, 18.74, 4.69)

Expanding a Derived Class

One of the most valuable features of class inheritance is that a child class can acquire new behaviors not available from the parent class. One of the options you have is to add new methods (and/or properties) to the new class. For example, you can add constructors to accommodate various ways to create objects from the derived class. Here is an example:

type Person(first, last) =
    member this.FirstName : string = first
    member this.LastName  : string = last

type Customer(first, last, acntNumber) =
    inherit Person(first, last)
        member this.AccountNumber : string = acntNumber
        member this.FullName = base.LastName + ", " + base.FirstName
        new() = Customer("John", "Doe", "0000-000-0000")
        new(first, last) = Customer(first, last, "0000-000-0000")

type Employee(emplNumber, first, last, acntNumber, employmentStatus, salary) =
    inherit Customer(first, last, acntNumber)
        member this.EmployeeNumber : string = emplNumber;
        member this.EmploymentStatus : string = "Full-Time";
        member this.Salary : int = salary
        new() = Employee("0000-0000", "John", "Doe", "0000-000-0000", "Unknown", 0)
        new(first, last) = Employee("0000-0000", first, last, "0000-000-0000", EmploymentStatus.Unknown, 0)
        new(emplNumber, first, last) = Employee(emplNumber, first, last, "0000-000-0000", EmploymentStatus.Unknown, 0)
        new(emplNumber, first, last, acntNumber) = Employee(emplNumber, first, last, acntNumber, EmploymentStatus.Unknown, 0)

You can use such constructors when creating an object. In the same way, you can expand a child class anyway you see fit.

A Sealed Class

A class is said to be sealed if no new class can be derived from it.

   
   
 

Home Copyright © 2009-2015, FunctionX Home