Abstract classes
Base classes that describe an idea but can’t be created themselves, with abstract members every child must implement.
abstract: they can’t be created with new, and they can declare abstract members that every concrete child must implement.
public abstract class Shape{ public string Name { get; } protected Shape(string name) => Name = name; public abstract double Area(); // no body: children MUST provide it public override string ToString() => $"{Name}: {Area():F2}"; // normal method using it} public class Rectangle : Shape{ public double Width { get; } public double Height { get; } public Rectangle(double w, double h) : base("Rectangle") { Width = w; Height = h; } public override double Area() => Width * Height;} public class Circle : Shape{ public double Radius { get; } public Circle(double r) : base("Circle") => Radius = r; public override double Area() => Math.PI * Radius * Radius;} var shapes = new List<Shape> { new Rectangle(4, 3), new Circle(1.5) };foreach (var s in shapes) Console.WriteLine(s);// var x = new Shape("?"); // error CS0144: cannot create an abstract class Output
Rectangle: 12.00 Circle: 7.07
The rules
An abstractclass can’t be instantiated, but it can have constructors (called by children throughbase(...)), fields, properties and normal methods.An abstractmethod has no body and is implicitly virtual. Only abstract classes can contain abstract members.A non-abstract child must overrideevery abstract member, or the code won’t compile (CS0534).You can still use the abstract type for variables, parameters and lists: List<Shape>.
The template method pattern
public abstract class ReportExporter{ // the fixed overall process public void Export(string path) { string body = BuildBody(); File.WriteAllText(path, Header() + body + Footer()); Console.WriteLine($"Saved {path}"); } protected virtual string Header() => "Steel Report\n"; // optional to change protected abstract string BuildBody(); // must be supplied protected virtual string Footer() => "\n-- end --";} public class CsvExporter : ReportExporter{ protected override string BuildBody() => "Mark,Length\nB1,6.0\n";} new CsvExporter().Export("report.csv"); Output
Saved report.csv
virtual vs abstract
| `virtual` | `abstract` | |
|---|---|---|
Practice
Vehicle with a Name and an abstract method double CostPerKm(), plus a normal method double TripCost(double km) that uses it. Implement Truck (₹28 / km) and Car (₹9 / km), and print the cost of a 120 km trip for each.
Show the solution
public abstract class Vehicle{ public string Name { get; } protected Vehicle(string name) => Name = name; public abstract double CostPerKm(); public double TripCost(double km) => km * CostPerKm();} public class Truck : Vehicle{ public Truck() : base("Truck") { } public override double CostPerKm() => 28;} public class Car : Vehicle{ public Car() : base("Car") { } public override double CostPerKm() => 9;} foreach (Vehicle v in new Vehicle[] { new Truck(), new Car() }) Console.WriteLine($"{v.Name}: Rs {v.TripCost(120)}"); Output
Truck: Rs 3360 Car: Rs 1080
Remember
An abstract class is an incomplete base class; you can’t newit.Abstract members have no body and must be overridden by concrete children. Abstract classes can still hold shared fields, constructors and methods. Use them when related classes share code but each must fill in some parts.