Characteristics of Inheritance
|
|
Namespaces and Inheritance
|
|
Imagine you had created a class named Person in a namespace
named People as follows:
Source File: Persons.cs |
using System;
namespace People
{
public class Person
{
private string _name;
private string _gdr;
public Person()
{
this._name = "Not Available";
this._gdr = "Unknown";
}
public Person(string name, string gender)
{
this._name = name;
this._gdr = gender;
}
private string FullName
{
get { return _name; }
set { _name = value; }
}
private string Gender
{
get { return _gdr; }
set { _gdr = value; }
}
}
}
|
If you decide to derive a class from it, remember that this
class belongs to a namespace. To inherit from this class, the compiler will need to know
the namespace in which the was created. Class inheritance that involves namespaces relies on
qualification, like the calling of the members of a namespace. To derive a class
from a class member of a namespace, type the name of the namespace, followed by
the period operator ".", and followed by the name of the base namespace.
Here is an example:
Source File: StaffMembers.cs
|
using System;
namespace HighSchool
{
public class Teacher : People.Person
{
private string _pos;
public Teacher()
{
this._pos = "Staff Member";
}
public Teacher(string pos)
{
this._pos = pos;
}
private string Position
{
get { return _pos; }
set { _pos = value; }
}
}
}
|
If you need to call the class that was defined in a
different namespace, remember to qualify its name with the scope access
operator. Here is an example:
Source File: Exercise.cs
|
using System;
class Exercise
{
static void Main()
{
People.Person man = new People.Person("Hermine Sandt", "Male");
HighSchool.Teacher staff = new HighSchool.Teacher("Vice Principal");
Console.WriteLine();
}
}
|
Alternatively, as mentioned in the past, to use the contents
of a namespace, prior to calling a member of that namespace, you can type the using
keyword followed by the name of the namespace. Here is an example:
Source File: Exercise.cs |
using System;
using People;
using HighSchool;
class Exercise
{
static void Main()
{
Person man = new Person("Hermine Sandt", "Male");
Teacher staff = new Teacher("Vice Principal");
Console.WriteLine();
}
}
|
Practical Learning: Using Inheritance With Namespaces |
|
- Open Notepad and type the following:
using System;
namespace FlatShapes
{
class Square
{
private double _side;
public Square()
{
_side = 0.00;
}
public Square(double s)
{
_side = s;
}
}
class Rectangle
{
double _length;
double _height;
public Rectangle()
{
_length = 0.00;
_height = 0.00;
}
public Rectangle(double L, double H)
{
_length = L;
_height = H;
}
}
}
|
- Save the file in a new folder named Shapes1
- Save the file itself as Regulars.cs
- Start another instance of Notepad and type the following:
using System;
class Exercise
{
static void Main()
{
FlatShapes.Square Sq = new FlatShapes.Square(24.55);
}
}
|
- Save the file as Exercise.cs in the same Shapes1 folder
- Open the Command Prompt and switch to the above Shapes1 folder
- To compile the project, type csc Exercise.cs Regulars.cs and press
Enter
- To execute the project, type Exercise and press Enter
- Return to Notepad
To maintain a privileged relationship with its
children, a parent class can make a set list of members available only to
classes derived from it. With this relationship, some members of a parent class have a
protected access level. Of course, as the class creator, it is your job to
specify this relationship.
To create a member that
derived classes only can access, type the protected keyword to its left. Here
are examples:
Source File: Persons.cs |
using System;
namespace People
{
public class Person
{
private string _name;
private string _gdr;
public Person()
{
this._name = "Not Available";
this._gdr = "Unknown";
}
public Person(string name, string gender)
{
this._name = name;
this._gdr = gender;
}
protected string FullName
{
get { return _name; }
set { _name = value; }
}
protected string Gender
{
get { return _gdr; }
set { _gdr = value; }
}
public void Show()
{
Console.WriteLine("Full Name: {0}", this.FullName);
Console.WriteLine("Gender: {0}", this.Gender);
}
}
}
|
You can access protected members only in derived classes.
Therefore, if you instantiate a class outside, you can call only public members:
Source File: Exercise.cs |
using System;
class Exercise
{
static void Main()
{
People.Person man = new People.Person("Hermine Sandt", "Male");
Console.WriteLine("Staff Member");
man.Show();
Console.WriteLine();
}
}
|
This would produce:
Staff Member
Full Name: Hermine Sandt
Gender: Male
We have just mentioned that you can create a new version of
a member in a derived class for a member that already exists in the parent
class. After doing this, when you call that member in your program, you need to
make sure that the right member gets called, the member in the base class or the
equivalent member in the derived class.
When you create a base class, if you anticipate that a
certain property or method would need to be redefined in the derived class, you
can indicate this to the compiler. On the other hand, while creating your
classes, if you find out that you are customizing a property of method that
already existed in the base class, you should let the compiler that you are
providing a new version. In both cases, the common member should be created as
virtual. To do this, in the base class, type the virtual keyword to the
left of the property or method. Based on this, the Area property of our Circle
class can be created as follows:
class Circle
{
public virtual double Area
{
get
{
return Radius * Radius * 3.14159;
}
}
}
In fact, in C#, unlike C++, if you omit the virtual keyword,
the compiler would display a warning.
When you derive a class from an abstract, since the
methods (if any) of the abstract class were not implemented, you must
implement each one of them in the derived class. When customizing virtual members in
a derived class, to indicate that a member is already virtual in the base class
and that you are defining a new version, type the override keyword to the
left of its declaration. For example, the Area property in our Sphere class can
be created as follows:
class Sphere : Circle
{
public override double Area
{
get
{
return 4 * Radius * Radius * 3.14159;
}
}
public double Volume
{
get
{
return 4 * 3.14159 * Radius * Radius * Radius;
}
}
}
In the same way, when implementing an abstract method
of a class, type the override keyword to its left.
Practical Learning: Using Virtual Members |
|
- Start a new instance of Notepad and type the following:
class ShapeDescription
{
public virtual string Description()
{
string Msg = "A quadrilateral is a geometric figure that has " +
"four sides and four angles.";
return Msg;
}
}
|
- Save the file as Quadrilaterals.cs in the Shapes1 folder
- Access the Regulars.cs file and override the Description method in the
FlatShapes.Square and the FlatShapes.Rectangle classes as follows:
using System;
namespace FlatShapes
{
class Square : ShapeDescription
{
private double _side;
public Square()
{
_side = 0.00;
}
public Square(double s)
{
_side = s;
}
public override string Description()
{
// Get the introduction from the parent
string Introduction = base.Description() +
"\nA square is a quadrilateral that has four " +
"equal sides and four right angles";
return Introduction;
}
}
class Rectangle : ShapeDescription
{
double _length;
double _height;
public Rectangle()
{
_length = 0.00;
_height = 0.00;
}
public Rectangle(double L, double H)
{
_length = L;
_height = H;
}
public override string Description()
{
// Get the introduction from the parent
string Introduction = base.Description();
string Msg = Introduction +
"\nA rectangle is a quadrilateral that has adjacent " +
"perpendicular sides. This implies that its four " +
"angles are right.";
return Msg;
}
}
}
|
- Save the Regulars.cs file
- To access the new methods, access the Exercise.cs and change it as
follows:
using System;
class Exercise
{
static void DisplaySquare(FlatShapes.Square S)
{
Console.WriteLine("Square Characteristics");
Console.WriteLine("Description: {0}", S.Description());
}
static void DisplayRectangle(FlatShapes.Rectangle R)
{
Console.WriteLine("Rectangle Characteristics");
Console.WriteLine("Description: {0}", R.Description());
}
static void Main()
{
FlatShapes.Square Sq = new FlatShapes.Square();
FlatShapes.Rectangle Rect = new FlatShapes.Rectangle();
Console.WriteLine("========================================");
DisplaySquare(Sq);
Console.WriteLine("========================================");
DisplayRectangle(Rect);
Console.WriteLine("========================================");
Console.WriteLine();
}
}
|
- Save the Exercise.cs
- Switch to the Command Prompt to the Shapes1 folder
- To compile the project, type csc Exercise.cs Regulars.cs
Quadrilaterals.cs and press Enter
- To execute the project, type Exercise and press Enter. This would
produce:
========================================
Square Characteristics
Description: A quadrilateral is a geometric figure that has four sides and four
angles.A square is a quadrilateral that has four equal sides and four right angles
========================================
Rectangle Characteristics
Description: A quadrilateral is a geometric figure that has four sides and four
angles.
A rectangle is a quadrilateral that has adjacent perpendicular sides. This implies
that its four angles are right.
========================================
|
- Return to Notepad
In C#, you can create a class whose role is only meant to
provide fundamental characteristics for other classes. This type of class cannot
be used to declare a variable of the object. Such a class is referred to as
abstract. Therefore, an abstract class can be created only to serve as a parent
class for others. To create an abstract class, type the abstract keyword to the left
of its name. Here is an example:
abstract class Ball
{
protected int TypeOfSport;
protected string Dimensions;
}
Practical Learning: Creating an Abstract Class |
|
- To create an abstract class, in the Regulars.cs class, type the abstract
keyword at the beginning of the class creation line:
abstract class ShapeDescription
{
public virtual string Description()
{
string Msg = "A quadrilateral is a geometric figure that has " +
"four sides and four angles.";
return Msg;
}
}
|
- Save the file
Abstract Properties and Methods
|
|
When creating a class that would mainly be used as base for
future inheritance, you can create one or more properties and make them
abstract. To do this, when creating the property, type the abstract
keyword to its left. Because you would not define the property, you can simply
type the get keyword and its semi-colon in the body of the property.
A method of a class also can be made abstract. An abstract
method can be a member of only an abstract class. If you make a method abstract
in a class, you must not implement the method. To create an abstract method, when creating its class, type
the abstract keyword to the left of the method's name. End the
declaration with a semi-colon and no body for the method since you cannot
implement it. Here is an example:
public abstract class Ball
{
protected int TypeOfSport;
protected string Dimensions;
public abstract CalculateArea();
}
In the same way, you can create as many properties and
methods as you see fit. You can choose what properties and methods to make
abstract. This is important for inheritance.
Practical Learning: Creating an Abstract Property |
|
- To create an abstract property, access the Quadrilaterals.cs file and
change its class as follows:
abstract class ShapeDescription
{
public abstract string Name { get; }
public virtual string Description()
{
string Msg = "A quadrilateral is a geometric figure that has " +
"four sides and four angles.";
return Msg;
}
}
|
- Save the Quadrilaterals.cs file
- To define the property, open the Regulars.cs file and change it as
follows:
using System;
namespace FlatShapes
{
class Square : ShapeDescription
{
private double _side;
public Square()
{
_side = 0.00;
}
public Square(double s)
{
_side = s;
}
public override string Name
{
get { return "Square"; }
}
public override string Description()
{
// Get the introduction from the parent
string Introduction = base.Description() +
"A square is a quadrilateral that has four " +
"equal sides and four right angles";
return Introduction;
}
}
class Rectangle : ShapeDescription
{
double _length;
double _height;
public Rectangle()
{
_length = 0.00;
_height = 0.00;
}
public Rectangle(double L, double H)
{
_length = L;
_height = H;
}
public override string Name
{
get { return "Rectangle"; }
}
public override string Description()
{
// Get the introduction from the parent
string Introduction = base.Description();
string Msg = Introduction +
"\nA rectangle is a quadrilateral that has adjacent " +
"perpendicular sides. This implies that its four " +
"angles are right.";
return Msg;
}
}
}
|
- Save the Regulars.cs file
- To include the new property in the test, access the Exercise.cs file and
change it as follows:
using System;
class Exercise
{
static void DisplaySquare(FlatShapes.Square S)
{
Console.WriteLine("Square Characteristics");
Console.WriteLine("Name: {0}", S.Name);
Console.WriteLine("Description: {0}", S.Description());
}
static void DisplayRectangle(FlatShapes.Rectangle R)
{
Console.WriteLine("Rectangle Characteristics");
Console.WriteLine("Name: {0}", R.Name);
Console.WriteLine("Description: {0}", R.Description());
}
static void Main()
{
FlatShapes.Square Sq = new FlatShapes.Square();
FlatShapes.Rectangle Rect = new FlatShapes.Rectangle();
Console.WriteLine("========================================");
DisplaySquare(Sq);
Console.WriteLine("========================================");
DisplayRectangle(Rect);
Console.WriteLine("========================================");
Console.WriteLine();
}
}
|
- Save the Exercise.cs
- To compile the project, type csc Exercise.cs Regulars.cs
Quadrilaterals.cs and press Enter
- To execute the project, type Exercise and press Enter. This would
produce:
========================================
Square Characteristics
Name: Square
Description: A quadrilateral is a geometric figure that has four sides and four
angles.A square is a quadrilateral that has four equal sides and four right angl
es
========================================
Rectangle Characteristics
Name: Rectangle
Description: A quadrilateral is a geometric figure that has four sides and four
angles.
A rectangle is a quadrilateral that has adjacent perpendicular sides. This impli
es that its four angles are right.
========================================
|
- Return to Notepad
Any of the classes we have used so far in our lessons
can be inherited from. If you create a certain class and don't want anybody to
derive another class from it, you can mark it as sealed. In other words, a
sealed class is one that cannot serve as base for another class.
To mark a class as sealed, type the sealed keyword to
its left. Here is an example:
public sealed class Ball
{
public int TypeOfSport;
public string Dimensions;
}
Imagine you start creating a class and, while implementing
or testing it, you find out that this particular class can be instead as a
general base that other classes can be derived from. An interface is a special
class whose purpose is to serve as a template that actual classes can be based
on.
An interface is primarily created like a class: it has a
name, a body and can have members. To create an interface, instead of the class
keyword, you use the interface keyword. By convention, the name of an interface
starts with I. Here is an example:
interface ICourtDimensions
{
}
Practical Learning: Introducing Interfaces |
|
- Access the Quadrilaterals.cs file. To create an interface, change the file
as follows:
interface IQuadrilateral
{
}
abstract class ShapeDescription
{
public abstract string Name { get; }
public virtual string Description()
{
string Msg = "A quadrilateral is a geometric figure that has " +
"four sides and four angles.";
return Msg;
}
}
|
- Save the file
The Members of an Interface
|
|
As done for a class, the members of an interface are listed
in its body. In an interface, you cannot declare fields like those we have used
in other classes. Instead, if you want some type of member variable, you can
create a property. If you create a property in an interface, you cannot define
that property. One of the rules of an interface is that you cannot define any of
its members. This is also valid for its properties. Therefore, if you create a
property in an interface:
- You can indicate that it would be read-only by adding it an empty getter.
Here is an example:
public interface ICourtDimensions
{
double Length { get; }
}
|
- You can indicate that it would be write-only. Here is an example:
public interface ICourtDimensions
{
double Length { set; }
}
|
- You can indicate that it would be used to write values to it and to read
values from it. Here is an example:
public interface ICourtDimensions
{
double Length { get; set; }
}
|
In the same way, you can create as many properties as you
judge them necessary in an interface. Besides the properties, an interface can
also have other types of members such as methods. Here is an example of an
interface that has one read-only property named NameOfSport, one read/write
property named NumberOfPlayers, and one method named SportCharacteristics:
public interface IBall
{
int NumberOfPlayers
{
get;
set;
}
string NameOfSport
{
get;
}
void SportCharacteristics();
}
Practical Learning: Creating Members of an Interface |
|
- To create a member int the new interface, access the Quadrilateral.cs file and
change it as follows:
interface IQuadrilateral
{
double Area { get; }
}
abstract class ShapeDescription
{
public abstract string Name { get; }
public virtual string Description()
{
string Msg = "A quadrilateral is a geometric figure that has " +
"four sides and four angles.";
return Msg;
}
}
|
- Save the file
An Interface as a Base Class
|
|
An interface is mostly used to lay a foundation for other
classes. For this reason, it is the prime candidate for class derivation. To
derive from an interface, use the same technique we have applied in inheritance
so far. Here is an example of a class named SportBall that derives from an
interface named ISportType:
public class SportBall : ISportType
{
int players;
string sport;
}
Just as you can derive a class from an interface, you can
create an interface that itself is based on another interface. Here is an
example:
public interface ISportType : IBall
{
SportCategory Type
{
get;
}
}
The C# language doesn't allow multiple inheritance which is
the ability to create a class based on more than one class. Multiple inheritance
is allowed only if the bases are interfaces. To create multiple inheritance,
separate the names of interface with a comma. Here is an example:
public interface ISportType : IBall, ICourtDimensions
{
SportCategory Type
{
get;
}
}
You can also involve a class as parent in a multiple
inheritance scenario but there must be only one class. Here is an example in
which a class called Sports derives from one class and various interfaces:
public interface Sports: Player, IBall, ICourtDimensions
{
}
Practical Learning: Inheriting From an Interface |
|
- To inherit an interface from another interface, access the Quadrilateral.cs file and change
it as follows:
interface IQuadrilateral
{
double Area { get; }
}
abstract class ShapeDescription
{
public abstract string Name { get; }
public virtual string Description()
{
string Msg = "A quadrilateral is a geometric figure that has " +
"four sides and four angles.";
return Msg;
}
}
interface IRightAngles : IQuadrilateral
{
double Base { get; set; }
double Height { get; set; }
double Perimeter { get; }
}
|
- Save the file
- To inherit a class from an interface, access the Regulars.cs file and
change it as follows:
using System;
namespace FlatShapes
{
class Square : ShapeDescription, IRightAngles
{
. . . No Change
}
class Rectangle : ShapeDescription, IRightAngles
{
. . . No Change
}
}
|
- Save the file
Implementation of Derived Classes of an Interface
|
|
After creating an interface, you can derive other interfaces
or other classes from it. If you are deriving other interfaces from an
interface, you can just proceed as you see fit. For example, you can add or not
add one or more new properties, you can add or not add one or more properties,
etc. Here is an example:
Source File: Preparation.cs |
public enum SportCategory
{
SinglePlayer,
Collective,
Unknown
}
public interface ICourtDimensions
{
double Length { get; set; }
double Width { get; set; }
}
public interface IBall
{
int NumberOfPlayers
{
get;
set;
}
string NameOfSport
{
get;
}
void SportCharacteristics();
}
public interface ISportType : IBall, ICourtDimensions
{
SportCategory Type
{
get;
}
}
|
If you derive a class, from an interface, you must implement
all properties that created in the interface. This means that you must define
them so that, when a variable is declared of that class, the properties have
meaning. In the same way, if you create a class that is based on an interface,
you must implement all methods that were declared in the interface. If you
derive a class from an interface that itself was derived from another interface,
in your class, you must define all properties that were created in the whole
lineage and you must implement all methods that were created in the parent and
grant-parent interfaces. Here is an example:
Source File: Sport.cs |
using System;
public class SportBall : ISportType
{
int players;
string sport;
SportCategory _type;
double Len;
double Wdt;
public SportBall(int nbr, SportCategory tp, string name)
{
players = nbr;
_type = tp;
sport = name;
}
public int NumberOfPlayers
{
get { return players;}
set { players = value;}
}
public string NameOfSport
{
get { return sport; }
}
public SportCategory Type
{
get { return _type; }
}
public double Length
{
get { return Len; }
set { Len = value; }
}
public double Width
{
get { return Wdt; }
set { Wdt = value; }
}
public void SportCharacteristics()
{
Console.WriteLine("Sport Characteristics");
Console.WriteLine("Name of Sport: {0}", NameOfSport);
Console.WriteLine("Type of Sport: {0}", Type);
Console.WriteLine("# of Players: {0}", NumberOfPlayers);
Console.WriteLine("Court Dimensions: {0}m x {1}m", Len, Wdt);
}
}
|
Once the class is ready, you can then use it as you see fit.
Here is an example:
|
|