It is logical to make the Area()
method an abstract one because at this point you don't really know what shape you are working on (circle, square, or triangle, for example), and thus you don't know how to calculate its area.
An abstract method is defined just like a normal method without the normal method block ({}
). Classes that inherit from a class containing abstract methods must provide the implementation for those methods.
The Rectangle
class defined earlier must now implement the Area()
abstract method, using the override
keyword:
public class Rectangle : Shape {
}
Instead of using the this
keyword to access the length
and width
properties, you can also use the base
keyword:
public class Rectangle : Shape {
public override double Area() {
}
}
The base
keyword is used to access members (such as properties and variables) of the base class from within a derived class. You can also use the base
keyword to access methods from the base class; here's an example:
public class Rectangle : Shape {
public override sealed double Area() {
return this.length * this.width;
//return base.length * base.width;
}
}
You can now use the Rectangle class like this:
Rectangle r = new Rectangle();
r.length = 4;
r.width = 5;
Console.WriteLine(r.Perimeter()); //---18---
Console.WriteLine(r.Area()); //---20---
An abstract method can only be defined in an abstract class.
The base keyword refers to theClass3
inherits from Class2
, which in turn inherits from Class1:
public class Class1 {
public virtual void PrintString() {
Console.WriteLine('Class1');
}
}
public class Class2: Class1 {
public override void PrintString() {
Console.WriteLine('Class2');
}
}
public class Class3 : Class2 {
public override void PrintString() {
}
}
In Class3
, the base.PrintString()
statement invokes the PrintString()
method defined in its parent, Class2
. The following statements verify this:
Class3 c3 = new Class3();
//---prints out 'Class2'---
c3.PrintString();
Virtual Methods
Using the Rectangle
class, you can find the perimeter and area of a rectangle with the Perimeter()
and Area()
methods, respectively. But what if you want to define a Circle
class? Obviously, the perimeter (circumference) of a circle is not the length multiply by its width. For simplicity, though, let's assume that the diameter of a circle can be represented by the Length
property.
The definition of Circle
will look like this:
public class Circle : Shape {}
However, the Perimeter()
method should be reimplemented as the circumference of a circle is defined to be 2*π*radius (or π*diameter). But the Perimeter()
method has already been defined in the base class Shape
. In this case, you need to indicate to the compiler that the Perimeter()
method in the Shape
class can be reimplemented by its derived class. To do so, you need to prefix the Perimeter()
method with the virtual
keyword to indicate that all derived classes have the option to change its implementation:
public abstract class Shape {
//---properties---
public double length { get; set; }
public double width { get; set; }
//---make this method as virtual---
return 2 * (this.length + this.width);
}
//---abstract method---
public abstract double Area();
}
The Circle
class now has to provide implementation for both the Perimeter()
and Area()
methods (note the use of the override
keyword):
public class Circle : Shape {