Object-Oriented Programming in C# .NET - Part 5





4.00/5 (7 votes)
A discussion of virtual and override members, overriding operators, interfaces and nested types in C#
Introduction
In the last part of Object-Oriented Programming, we will go through the following:
- Virtual and Override Members
- Overriding Operators
- Interfaces
- Nested Types
What are Virtual and Override Members?
Virtual and Override members (methods, properties) are another kind of polymorphism. When you derive from a base class, that base class may have some virtual members and allow you to override them. That is, change their implementation so that when called by an object of your class does a different thing. The best way of understanding it is through an example. Suppose you derive from a base class named Car
. This Car
class possesses a method named Accelerate
:
class Car
{
private int speed;
public void Accelerate()
{
speed += 10;
}
}
When you instantiate an object of type car
and call the Accelerate
method, the value stored in speed will increase by 10
. Now, you want to create a much faster Car
class that when its Accelerate
method is called, its speed increases by 30
. And, of course, this new car
derives from the base car
class:
class MuchFasterCar:Car
{
private int speed;
public void Accelerate()
{
speed += 30;
Console.WriteLine ( speed );
}
}
If you build the solution, you will get a warning. The solution to this warning is that the Accelerate
method in Car
class should be declared as virtual
which allows you to override it within the MuchFasterClass
:
class Car
{
private int speed;
public virtual void Accelerate()
{
speed += 10;
Console.WriteLine (speed );
}
}
class MuchFasterCar:Car
{
private int speed;
public override void Accelerate()
{
speed += 30;
Console.WriteLine ( speed );
}
}
This means that the Car
and the MuchFasterCar
have their own specific implementation for Accelerate
method. Your don’t have to override each single method, but if you don’t you will get a warning:
class Car
{
private int speed;
public virtual void Accelerate()
{
speed += 10;
Console.WriteLine (speed );
}
}
class MuchFasterCar:Car
{
private int speed;
public void Accelerate()
{
speed += 30;
Console.WriteLine ( speed );
}
}
You also have the option of marking the method as new
which hides the base’s virtual
method without generating any warnings:
class Car
{
private int speed;
public virtual void Accelerate()
{
speed += 10;
Console.WriteLine (speed );
}
}
class MuchFasterCar:Car
{
private int speed;
public new void Accelerate()
{
speed += 30;
Console.WriteLine ( speed );
}
}
Overriding is not limited to methods. It also happens on properties:
class Car
{
private int speed;
public virtual int Speed
{
get { return speed; }
set { speed = value; }
}
public virtual void Accelerate()
{
speed += 10;
Console.WriteLine (Speed );
}
}
class MuchFasterCar:Car
{
private int muchFasterSpeed;
public override int Speed
{
get
{
return muchFasterSpeed;
}
set
{
muchFasterSpeed = value;
}
}
public new void Accelerate()
{
muchFasterSpeed += 30;
Console.WriteLine ( Speed );
}
}
In the above example, the Speed
properties which is declared as virtual
in Car
class is overridden in MuchFasterCar
class.
What are Overriding Operators?
Have you ever thought of the way the +
operator works. When used on two integers, it simply works like an Add
method in a Math
class.
class Program
{
static void Main(string[] args)
{
int a = 3 + 2;
Console.WriteLine (a);
Console.ReadKey ();
}
}
When used on string
s, it concats them (appends the last string
to the end of the one before last):
class Program
{
static void Main(string[] args)
{
string s = "Hello " + "World!";
Console.WriteLine (s);
Console.ReadKey ();
}
}
So, as you see, the +
operator does different things based on the type it’s working on. What if you want to make the +
operator do yet another different thing on objects of your class. Suppose you have a Point
class which has an X
and Y
coordinates. You want to override the +
sign on this Point
class so that when it’s applied to objects of type Point
, it simply adds the X
s and Y
s and return a new Point
object:
class Point
{
private int x;
public int X
{
get { return x; }
set { x = value; }
}
private int y;
public int Y
{
get { return y; }
set { y = value; }
}
public Point(int xVal,int yVal)
{
X = xVal;
Y = yVal;
}
public static Point operator +(Point a,Point b)
{
Point result = new Point ( a.X + b.X, a.Y + b.Y );
return result;
}
}
Note the signature of the method that overrides the +
operator. It’s declared as public
and static
(always must be), it returns an object of type Point
, it has the operator
keyword, it specifies the name of the operator that is overriding. Now, look at the following code:
class Program
{
static void Main(string[] args)
{
Point p1 = new Point ( 2, 4 );
Point p2 = new Point ( 5, 6 );
Point p3 = p1 + p2;
Console.WriteLine (p3.X );
Console.WriteLine (p3.Y );
Console.ReadKey ();
}
}
Run the solution and see the results. You can override the *,/,- operators similarly.
What are Interfaces?
Interfaces are like contracts. If your class is to have a certain capability, it must override a certain interface. Another use of interfaces is providing multiple inheritance, which is impossible in C# using class derivation. That means that you can derive from only and only one class but you can implement as many interfaces as you desire. Suppose you want to make an Animal
hierarchy. You create a base abstract
class named Animal
that every class in the hierarchy derives from. The reason to create the Animal
class as abstract
is that it should not be instantiated (an abstract
class cannot be instantiated.). Now some animals are carnivore, some are herbivore, some are reptiles. You cannot make a class, say, Crocodile
derive from Animal
, Carnivore
, Reptile
. Instead, you declare everything except the base Animal
class as interfaces. Therefore, the Crocodile
class is an Animal
which implements the Carnivore
, Reptile
interfaces (which are also like contracts. If the Crocodile
is to be thought as a carnivore
and a reptile
, it must implement a certain, in this case Carnivore
and Reptile
, interfaces.). I won’t write the codes for all of these classes, but I assure you will get the idea:
abstract class Animal
{
public abstract void Feed();
public abstract void Move();
}
interface ICarnivore
{
void Hunt();
}
interface IHerbivore
{
void Chew();
}
interface IReptile
{
void Crawl();
}
class Crocodile:Animal,IReptile,ICarnivore
{
}
class Lion:Animal,ICarnivore
{
}
Every single member that is within an interface must be implemented by the class which uses it. For example, the code of the Lion
class would be as follows:
class Lion:Animal,ICarnivore
{
public override void Feed()
{
Console.WriteLine ("Feeding");
}
public override void Move()
{
Console.WriteLine ("Moving");
}
public void Hunt()
{
Console.WriteLine ( "Hunting" );
}
}
There are lots of built-in interfaces which you can use to give your class additional functionality. For instance, if you want your class to be sortable (if you have an array containing objects of your class and you want to sort that array), you must add IComparable
interface to your class and implement its CompareTo
method.
One interesting thing about interfaces is that you can assign an object of a particular type to an interface provided that class implements that interface as you can do the same with an abstract
class:
class Program
{
static void Main(string[] args)
{
ICarnivore l = new Lion ();
Animal a = new Lion ();
}
}
What are Nested Types?
You can declare a class within another class. The inner class in called the nested class and the outer class is called the nesting class. This is done when the nested class is meaningless out of the scope of the nesting class. In UML, this is called composition relationship. Suppose we want to declare a class named Human
. Humans have hearts. Now, Heart
is the other class we want to create. However, let’s assume that a heart is meaningless if there is no human. Therefore, we create the Heart
class within our Human
class:
public class Human
{
int age;
public int Age
{
get { return age; }
set { age = value; }
}
public class Heart
{
Human owner;
public Human Owner
{
get { return owner; }
set { owner = value; }
}
public Heart(Human ownerVal)
{
Owner = ownerVal;
}
bool isHealthy;
public bool IsHealthy
{
get { return isHealthy; }
set { isHealthy = value; }
}
}
}
Now, we can use these classes as follows:
class Program
{
static void Main(string[] args)
{
Human human = new Human ();
human.Age = 12;
Human.Heart heart = new Human.Heart ( human );
Console.WriteLine (heart.Owner.Age );
Console.ReadKey ();
}
}
That’s all for the last part of this article. Thank you for spending time studying this series of articles. Hope you have learnt helpful and interesting things.
History
- 5th July, 2011: Initial version