Besides making a class abstract by using the abstract keyword, you can also create abstract methods. An abstract method has no implementation, and its implementation is left to the classes that inherit from the class that defines it. Using the Shape
class as an example, you can now define an abstract method called Area()
that calculates the area of a shape:
public abstract class Shape {
//---properties---
public double length { get; set; }
public double width { get; set; }
//---method---
public double Perimeter() {
return 2 * (this.length + this.width);
}
//---abstract method---
public abstract double Area();
}
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 {
//---provide the implementation for the abstract method---
public override double Area() {
return this.length * this.width;
}
}
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() {
return base.length * base.width;
}
}
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;
}
public override double Perimeter() {
//---invokes the Perimeter() method in the Shape class---
return base.Perimeter();
}
}
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 the parent class of a derived class, not the root class. Consider the following example where you have three classes — Class3
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() {
base.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();
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---
public virtual double Perimeter() {
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 {
//---provide the implementation for the abstract method---
public override double Perimeter() {
return Math.PI * (this.length);
}
//---provide the implementation for the virtual method---
public override double Area() {
return Math.PI * Math.Pow(this.length/2, 2);
}
}
Bear in mind that when overriding a method in the base class, the new method must have the same signature (parameter) as the overridden method. For example, the following is not allowed because the new Perimeter()
method has a single input parameter, but this signature does not match that of the Perimeter()
method defined in the base class ( Shape
):
public class Circle : Shape {
//---signature does not match Perimeter() in base class---
public override double Perimeter(int Diameter) {
//...
}
}
If you need to implement another new method also called Perimeter()
in the Circle
class but with a different signature, use the new keyword, like this:
public class Circle : Shape {
//---a new Perimeter() method---
public new double Perimeter(int diameter) {
Читать дальше