C# 继承
本章将详细介绍面向对象编程的第二个核心特性——继承,包括基类和派生类、方法重写、base 关键字等概念,帮助你实现代码重用和扩展。
继承的基本概念
什么是继承
csharp
// 继承允许一个类(派生类)从另一个类(基类)继承成员
// 语法:class 派生类 : 基类
// 基类(父类)
public class Animal
{
protected string name;
protected int age;
public Animal(string name, int age)
{
this.name = name;
this.age = age;
Console.WriteLine($"Animal 构造函数: {name}");
}
public string Name => name;
public int Age => age;
public virtual void Eat()
{
Console.WriteLine($"{name} 正在吃东西");
}
public virtual void Sleep()
{
Console.WriteLine($"{name} 正在睡觉");
}
public virtual void MakeSound()
{
Console.WriteLine($"{name} 发出声音");
}
public void DisplayInfo()
{
Console.WriteLine($"动物信息: {name}, {age}岁");
}
}
// 派生类(子类)
public class Dog : Animal
{
private string breed;
public Dog(string name, int age, string breed) : base(name, age)
{
this.breed = breed;
Console.WriteLine($"Dog 构造函数: {name}, {breed}");
}
public string Breed => breed;
// 重写基类方法
public override void MakeSound()
{
Console.WriteLine($"{name} 汪汪叫");
}
// 新增方法
public void Fetch()
{
Console.WriteLine($"{name} 正在捡球");
}
public void DisplayDogInfo()
{
DisplayInfo(); // 调用基类方法
Console.WriteLine($"品种: {breed}");
}
}
public class Cat : Animal
{
private bool isIndoor;
public Cat(string name, int age, bool isIndoor) : base(name, age)
{
this.isIndoor = isIndoor;
Console.WriteLine($"Cat 构造函数: {name}");
}
public bool IsIndoor => isIndoor;
public override void MakeSound()
{
Console.WriteLine($"{name} 喵喵叫");
}
public void Climb()
{
Console.WriteLine($"{name} 正在爬树");
}
// 重写多个方法
public override void Sleep()
{
Console.WriteLine($"{name} 蜷缩着睡觉");
}
}
static void BasicInheritanceDemo()
{
Console.WriteLine("=== 基本继承演示 ===");
// 创建派生类对象
Dog dog = new Dog("旺财", 3, "金毛");
Cat cat = new Cat("咪咪", 2, true);
Console.WriteLine("\n狗的行为:");
dog.DisplayDogInfo();
dog.Eat(); // 继承的方法
dog.MakeSound(); // 重写的方法
dog.Fetch(); // 新增的方法
Console.WriteLine("\n猫的行为:");
cat.DisplayInfo(); // 继承的方法
cat.MakeSound(); // 重写的方法
cat.Sleep(); // 重写的方法
cat.Climb(); // 新增的方法
}继承的特点
csharp
// 继承的特点演示
public class Vehicle
{
protected string brand;
protected int year;
protected decimal price;
public Vehicle(string brand, int year, decimal price)
{
this.brand = brand;
this.year = year;
this.price = price;
}
// 公共属性 - 派生类可以访问
public string Brand => brand;
public int Year => year;
public decimal Price => price;
// 虚方法 - 可以被重写
public virtual void Start()
{
Console.WriteLine($"{brand} 启动了");
}
public virtual void Stop()
{
Console.WriteLine($"{brand} 停止了");
}
// 普通方法 - 不能被重写,但可以被隐藏
public void DisplayBasicInfo()
{
Console.WriteLine($"车辆: {brand} {year}年 价格: {price:C}");
}
// 受保护的方法 - 只有派生类可以访问
protected void InternalDiagnostic()
{
Console.WriteLine("执行内部诊断...");
}
}
public class Car : Vehicle
{
private int doors;
private string fuelType;
public Car(string brand, int year, decimal price, int doors, string fuelType)
: base(brand, year, price)
{
this.doors = doors;
this.fuelType = fuelType;
}
public int Doors => doors;
public string FuelType => fuelType;
// 重写基类方法
public override void Start()
{
InternalDiagnostic(); // 调用受保护的基类方法
Console.WriteLine($"{brand} 汽车启动,{doors}门 {fuelType}");
}
// 新增方法
public void OpenTrunk()
{
Console.WriteLine($"{brand} 打开后备箱");
}
public void DisplayCarInfo()
{
DisplayBasicInfo(); // 调用基类方法
Console.WriteLine($"门数: {doors}, 燃料类型: {fuelType}");
}
}
public class Motorcycle : Vehicle
{
private int engineSize;
private bool hasSidecar;
public Motorcycle(string brand, int year, decimal price, int engineSize, bool hasSidecar)
: base(brand, year, price)
{
this.engineSize = engineSize;
this.hasSidecar = hasSidecar;
}
public int EngineSize => engineSize;
public bool HasSidecar => hasSidecar;
public override void Start()
{
Console.WriteLine($"{brand} 摩托车启动,{engineSize}cc引擎");
}
public void Wheelie()
{
Console.WriteLine($"{brand} 做后轮着地特技");
}
}
static void InheritanceCharacteristicsDemo()
{
Console.WriteLine("=== 继承特性演示 ===");
Car car = new Car("丰田", 2023, 200000m, 4, "汽油");
Motorcycle motorcycle = new Motorcycle("哈雷", 2022, 150000m, 1200, false);
Console.WriteLine("汽车信息:");
car.DisplayCarInfo();
car.Start();
car.OpenTrunk();
car.Stop();
Console.WriteLine("\n摩托车信息:");
motorcycle.DisplayBasicInfo();
motorcycle.Start();
motorcycle.Wheelie();
motorcycle.Stop();
}base 关键字
调用基类构造函数
csharp
public class Person
{
protected string firstName;
protected string lastName;
protected DateTime birthDate;
// 基类构造函数
public Person(string firstName, string lastName, DateTime birthDate)
{
this.firstName = firstName;
this.lastName = lastName;
this.birthDate = birthDate;
Console.WriteLine($"Person 构造函数: {firstName} {lastName}");
}
public string FullName => $"{firstName} {lastName}";
public int Age => DateTime.Now.Year - birthDate.Year;
public virtual void Introduce()
{
Console.WriteLine($"我是 {FullName},{Age} 岁");
}
}
public class Student : Person
{
private string studentId;
private string major;
private double gpa;
// 派生类构造函数必须调用基类构造函数
public Student(string firstName, string lastName, DateTime birthDate,
string studentId, string major)
: base(firstName, lastName, birthDate) // 调用基类构造函数
{
this.studentId = studentId;
this.major = major;
this.gpa = 0.0;
Console.WriteLine($"Student 构造函数: {studentId}");
}
public string StudentId => studentId;
public string Major => major;
public double GPA => gpa;
public void SetGPA(double gpa)
{
this.gpa = Math.Max(0.0, Math.Min(4.0, gpa));
}
// 重写基类方法,同时调用基类实现
public override void Introduce()
{
base.Introduce(); // 调用基类的 Introduce 方法
Console.WriteLine($"我是学生,学号: {studentId},专业: {major},GPA: {gpa:F2}");
}
}
public class Teacher : Person
{
private string employeeId;
private string department;
private decimal salary;
public Teacher(string firstName, string lastName, DateTime birthDate,
string employeeId, string department, decimal salary)
: base(firstName, lastName, birthDate)
{
this.employeeId = employeeId;
this.department = department;
this.salary = salary;
Console.WriteLine($"Teacher 构造函数: {employeeId}");
}
public string EmployeeId => employeeId;
public string Department => department;
public decimal Salary => salary;
public override void Introduce()
{
base.Introduce();
Console.WriteLine($"我是教师,工号: {employeeId},部门: {department}");
}
public void GiveLecture(string subject)
{
Console.WriteLine($"{FullName} 正在讲授 {subject}");
}
}
static void BaseKeywordDemo()
{
Console.WriteLine("=== base 关键字演示 ===");
Student student = new Student("张", "三", new DateTime(2000, 5, 15),
"S2023001", "计算机科学");
student.SetGPA(3.75);
Teacher teacher = new Teacher("李", "四", new DateTime(1980, 3, 20),
"T001", "计算机系", 80000m);
Console.WriteLine("\n学生介绍:");
student.Introduce();
Console.WriteLine("\n教师介绍:");
teacher.Introduce();
teacher.GiveLecture("C# 编程");
}调用基类方法
csharp
public class Shape
{
protected double x, y;
public Shape(double x, double y)
{
this.x = x;
this.y = y;
}
public virtual double CalculateArea()
{
return 0; // 基类默认实现
}
public virtual double CalculatePerimeter()
{
return 0; // 基类默认实现
}
public virtual void DisplayInfo()
{
Console.WriteLine($"形状位置: ({x}, {y})");
}
}
public class Rectangle : Shape
{
protected double width, height;
public Rectangle(double x, double y, double width, double height)
: base(x, y)
{
this.width = width;
this.height = height;
}
public override double CalculateArea()
{
return width * height;
}
public override double CalculatePerimeter()
{
return 2 * (width + height);
}
public override void DisplayInfo()
{
base.DisplayInfo(); // 调用基类方法
Console.WriteLine($"矩形: 宽度 {width}, 高度 {height}");
Console.WriteLine($"面积: {CalculateArea()}, 周长: {CalculatePerimeter()}");
}
}
public class Square : Rectangle
{
public Square(double x, double y, double side)
: base(x, y, side, side) // 调用父类构造函数
{
}
public override void DisplayInfo()
{
// 调用基类的 DisplayInfo,但跳过 Rectangle 的实现
// 直接调用 Shape 的 DisplayInfo
Console.WriteLine($"形状位置: ({x}, {y})");
Console.WriteLine($"正方形: 边长 {width}");
Console.WriteLine($"面积: {CalculateArea()}, 周长: {CalculatePerimeter()}");
}
}
public class Circle : Shape
{
private double radius;
public Circle(double x, double y, double radius) : base(x, y)
{
this.radius = radius;
}
public override double CalculateArea()
{
return Math.PI * radius * radius;
}
public override double CalculatePerimeter()
{
return 2 * Math.PI * radius;
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"圆形: 半径 {radius}");
Console.WriteLine($"面积: {CalculateArea():F2}, 周长: {CalculatePerimeter():F2}");
}
}
static void BaseMethodCallDemo()
{
Console.WriteLine("=== 基类方法调用演示 ===");
Rectangle rectangle = new Rectangle(0, 0, 5, 3);
Square square = new Square(10, 10, 4);
Circle circle = new Circle(5, 5, 2.5);
Console.WriteLine("矩形信息:");
rectangle.DisplayInfo();
Console.WriteLine("\n正方形信息:");
square.DisplayInfo();
Console.WriteLine("\n圆形信息:");
circle.DisplayInfo();
}方法重写和隐藏
virtual、override 和 new 关键字
csharp
public class BaseClass
{
public virtual void VirtualMethod()
{
Console.WriteLine("BaseClass.VirtualMethod()");
}
public void NonVirtualMethod()
{
Console.WriteLine("BaseClass.NonVirtualMethod()");
}
public virtual void MethodToHide()
{
Console.WriteLine("BaseClass.MethodToHide()");
}
}
public class DerivedClass : BaseClass
{
// 重写虚方法
public override void VirtualMethod()
{
Console.WriteLine("DerivedClass.VirtualMethod() - 重写");
base.VirtualMethod(); // 可选:调用基类实现
}
// 隐藏非虚方法(编译器会警告)
public new void NonVirtualMethod()
{
Console.WriteLine("DerivedClass.NonVirtualMethod() - 隐藏");
}
// 使用 new 关键字显式隐藏
public new void MethodToHide()
{
Console.WriteLine("DerivedClass.MethodToHide() - 显式隐藏");
}
}
public class FurtherDerived : DerivedClass
{
// 可以继续重写
public override void VirtualMethod()
{
Console.WriteLine("FurtherDerived.VirtualMethod() - 进一步重写");
base.VirtualMethod(); // 调用 DerivedClass 的实现
}
}
static void OverrideVsHideDemo()
{
Console.WriteLine("=== 方法重写 vs 隐藏演示 ===");
BaseClass baseObj = new BaseClass();
DerivedClass derivedObj = new DerivedClass();
FurtherDerived furtherObj = new FurtherDerived();
// 多态性:基类引用指向派生类对象
BaseClass polyObj1 = new DerivedClass();
BaseClass polyObj2 = new FurtherDerived();
Console.WriteLine("1. 直接调用:");
baseObj.VirtualMethod();
derivedObj.VirtualMethod();
furtherObj.VirtualMethod();
Console.WriteLine("\n2. 多态调用 (重写方法):");
polyObj1.VirtualMethod(); // 调用 DerivedClass 的重写版本
polyObj2.VirtualMethod(); // 调用 FurtherDerived 的重写版本
Console.WriteLine("\n3. 非虚方法:");
baseObj.NonVirtualMethod();
derivedObj.NonVirtualMethod();
polyObj1.NonVirtualMethod(); // 调用基类版本,不是派生类版本
Console.WriteLine("\n4. 隐藏方法:");
baseObj.MethodToHide();
derivedObj.MethodToHide();
polyObj1.MethodToHide(); // 调用基类版本,因为使用了 new
}sealed 关键字
csharp
public class SealedMethodExample
{
public virtual void CanBeOverridden()
{
Console.WriteLine("SealedMethodExample.CanBeOverridden()");
}
}
public class MiddleClass : SealedMethodExample
{
// 重写并密封方法,防止进一步重写
public sealed override void CanBeOverridden()
{
Console.WriteLine("MiddleClass.CanBeOverridden() - 已密封");
base.CanBeOverridden();
}
}
public class FinalClass : MiddleClass
{
// 编译错误:不能重写密封方法
// public override void CanBeOverridden() { }
// 但可以隐藏
public new void CanBeOverridden()
{
Console.WriteLine("FinalClass.CanBeOverridden() - 隐藏版本");
}
}
// 密封类 - 不能被继承
public sealed class SealedClass
{
public void SomeMethod()
{
Console.WriteLine("SealedClass.SomeMethod()");
}
}
// 编译错误:不能继承密封类
// public class CannotInherit : SealedClass { }
static void SealedDemo()
{
Console.WriteLine("=== sealed 关键字演示 ===");
SealedMethodExample original = new SealedMethodExample();
MiddleClass middle = new MiddleClass();
FinalClass final = new FinalClass();
// 多态调用
SealedMethodExample poly1 = new MiddleClass();
SealedMethodExample poly2 = new FinalClass();
Console.WriteLine("直接调用:");
original.CanBeOverridden();
middle.CanBeOverridden();
final.CanBeOverridden(); // 调用隐藏版本
Console.WriteLine("\n多态调用:");
poly1.CanBeOverridden(); // 调用 MiddleClass 版本
poly2.CanBeOverridden(); // 调用 MiddleClass 版本(不是 FinalClass 的隐藏版本)
}抽象类和抽象方法
抽象类的定义和使用
csharp
// 抽象类 - 不能被实例化
public abstract class Employee
{
protected string name;
protected string id;
protected DateTime hireDate;
public Employee(string name, string id, DateTime hireDate)
{
this.name = name;
this.id = id;
this.hireDate = hireDate;
}
// 普通属性
public string Name => name;
public string Id => id;
public DateTime HireDate => hireDate;
public int YearsOfService => DateTime.Now.Year - hireDate.Year;
// 抽象方法 - 必须在派生类中实现
public abstract decimal CalculateSalary();
public abstract string GetJobTitle();
// 虚方法 - 可以在派生类中重写
public virtual void DisplayInfo()
{
Console.WriteLine($"员工: {name} ({id})");
Console.WriteLine($"入职日期: {hireDate:yyyy-MM-dd}");
Console.WriteLine($"工作年限: {YearsOfService} 年");
Console.WriteLine($"职位: {GetJobTitle()}");
Console.WriteLine($"薪资: {CalculateSalary():C}");
}
// 普通方法
public void ClockIn()
{
Console.WriteLine($"{name} 已打卡上班 - {DateTime.Now:HH:mm:ss}");
}
public void ClockOut()
{
Console.WriteLine($"{name} 已打卡下班 - {DateTime.Now:HH:mm:ss}");
}
}
// 具体实现类
public class FullTimeEmployee : Employee
{
private decimal annualSalary;
private decimal bonus;
public FullTimeEmployee(string name, string id, DateTime hireDate, decimal annualSalary)
: base(name, id, hireDate)
{
this.annualSalary = annualSalary;
this.bonus = 0;
}
public decimal AnnualSalary => annualSalary;
public decimal Bonus => bonus;
public void SetBonus(decimal bonus)
{
this.bonus = Math.Max(0, bonus);
}
// 实现抽象方法
public override decimal CalculateSalary()
{
return (annualSalary + bonus) / 12; // 月薪
}
public override string GetJobTitle()
{
return "全职员工";
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"年薪: {annualSalary:C}");
if (bonus > 0)
Console.WriteLine($"奖金: {bonus:C}");
}
}
public class PartTimeEmployee : Employee
{
private decimal hourlyRate;
private int hoursWorked;
public PartTimeEmployee(string name, string id, DateTime hireDate, decimal hourlyRate)
: base(name, id, hireDate)
{
this.hourlyRate = hourlyRate;
this.hoursWorked = 0;
}
public decimal HourlyRate => hourlyRate;
public int HoursWorked => hoursWorked;
public void LogHours(int hours)
{
hoursWorked += Math.Max(0, hours);
}
public void ResetHours()
{
hoursWorked = 0;
}
public override decimal CalculateSalary()
{
return hourlyRate * hoursWorked;
}
public override string GetJobTitle()
{
return "兼职员工";
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"时薪: {hourlyRate:C}");
Console.WriteLine($"工作小时: {hoursWorked}");
}
}
public class Contractor : Employee
{
private decimal projectRate;
private int projectsCompleted;
public Contractor(string name, string id, DateTime hireDate, decimal projectRate)
: base(name, id, hireDate)
{
this.projectRate = projectRate;
this.projectsCompleted = 0;
}
public decimal ProjectRate => projectRate;
public int ProjectsCompleted => projectsCompleted;
public void CompleteProject()
{
projectsCompleted++;
Console.WriteLine($"{name} 完成了一个项目,总计: {projectsCompleted}");
}
public override decimal CalculateSalary()
{
return projectRate * projectsCompleted;
}
public override string GetJobTitle()
{
return "合同工";
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"项目费率: {projectRate:C}");
Console.WriteLine($"完成项目: {projectsCompleted}");
}
}
static void AbstractClassDemo()
{
Console.WriteLine("=== 抽象类演示 ===");
// Employee employee = new Employee(); // 编译错误:不能实例化抽象类
// 创建具体实现的对象
FullTimeEmployee fullTime = new FullTimeEmployee("张三", "FT001",
new DateTime(2020, 1, 15), 120000m);
fullTime.SetBonus(10000m);
PartTimeEmployee partTime = new PartTimeEmployee("李四", "PT001",
new DateTime(2023, 6, 1), 50m);
partTime.LogHours(80);
Contractor contractor = new Contractor("王五", "CT001",
new DateTime(2023, 3, 10), 5000m);
contractor.CompleteProject();
contractor.CompleteProject();
// 多态性:使用基类引用
Employee[] employees = { fullTime, partTime, contractor };
foreach (Employee emp in employees)
{
Console.WriteLine($"\n=== {emp.Name} ===");
emp.ClockIn();
emp.DisplayInfo();
emp.ClockOut();
}
}实践示例
示例 1:图形绘制系统
csharp
using System;
using System.Collections.Generic;
// 抽象基类
public abstract class Drawable
{
protected string name;
protected ConsoleColor color;
protected bool isVisible;
public Drawable(string name, ConsoleColor color = ConsoleColor.White)
{
this.name = name;
this.color = color;
this.isVisible = true;
}
public string Name => name;
public ConsoleColor Color => color;
public bool IsVisible => isVisible;
// 抽象方法 - 必须实现
public abstract void Draw();
public abstract double CalculateArea();
public abstract void Move(int deltaX, int deltaY);
// 虚方法 - 可以重写
public virtual void Show()
{
isVisible = true;
Console.WriteLine($"{name} 已显示");
}
public virtual void Hide()
{
isVisible = false;
Console.WriteLine($"{name} 已隐藏");
}
public virtual void SetColor(ConsoleColor newColor)
{
color = newColor;
Console.WriteLine($"{name} 颜色已改为 {newColor}");
}
// 模板方法模式
public void Render()
{
if (isVisible)
{
Console.ForegroundColor = color;
Draw();
Console.ResetColor();
}
}
}
public class Point : Drawable
{
protected int x, y;
public Point(string name, int x, int y, ConsoleColor color = ConsoleColor.White)
: base(name, color)
{
this.x = x;
this.y = y;
}
public int X => x;
public int Y => y;
public override void Draw()
{
Console.WriteLine($"在 ({x}, {y}) 绘制点 {name}");
}
public override double CalculateArea()
{
return 0; // 点没有面积
}
public override void Move(int deltaX, int deltaY)
{
x += deltaX;
y += deltaY;
Console.WriteLine($"{name} 移动到 ({x}, {y})");
}
public double DistanceTo(Point other)
{
return Math.Sqrt(Math.Pow(x - other.x, 2) + Math.Pow(y - other.y, 2));
}
}
public class Line : Drawable
{
protected Point start, end;
public Line(string name, Point start, Point end, ConsoleColor color = ConsoleColor.White)
: base(name, color)
{
this.start = start;
this.end = end;
}
public Point Start => start;
public Point End => end;
public override void Draw()
{
Console.WriteLine($"绘制线段 {name}: ({start.X}, {start.Y}) -> ({end.X}, {end.Y})");
}
public override double CalculateArea()
{
return 0; // 线段没有面积
}
public override void Move(int deltaX, int deltaY)
{
start.Move(deltaX, deltaY);
end.Move(deltaX, deltaY);
Console.WriteLine($"线段 {name} 已移动");
}
public double Length => start.DistanceTo(end);
}
public class Rectangle : Drawable
{
protected Point topLeft;
protected int width, height;
public Rectangle(string name, Point topLeft, int width, int height,
ConsoleColor color = ConsoleColor.White)
: base(name, color)
{
this.topLeft = topLeft;
this.width = width;
this.height = height;
}
public Point TopLeft => topLeft;
public int Width => width;
public int Height => height;
public override void Draw()
{
Console.WriteLine($"绘制矩形 {name}: 左上角({topLeft.X}, {topLeft.Y}), " +
$"宽度{width}, 高度{height}");
// 简单的ASCII艺术绘制
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (i == 0 || i == height - 1 || j == 0 || j == width - 1)
Console.Write("*");
else
Console.Write(" ");
}
Console.WriteLine();
}
}
public override double CalculateArea()
{
return width * height;
}
public override void Move(int deltaX, int deltaY)
{
topLeft.Move(deltaX, deltaY);
Console.WriteLine($"矩形 {name} 已移动");
}
public double CalculatePerimeter()
{
return 2 * (width + height);
}
}
public class Circle : Drawable
{
protected Point center;
protected double radius;
public Circle(string name, Point center, double radius,
ConsoleColor color = ConsoleColor.White)
: base(name, color)
{
this.center = center;
this.radius = radius;
}
public Point Center => center;
public double Radius => radius;
public override void Draw()
{
Console.WriteLine($"绘制圆形 {name}: 圆心({center.X}, {center.Y}), 半径{radius}");
// 简单的圆形绘制
int size = (int)(radius * 2) + 1;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
double distance = Math.Sqrt(Math.Pow(i - radius, 2) + Math.Pow(j - radius, 2));
if (Math.Abs(distance - radius) < 0.5)
Console.Write("*");
else
Console.Write(" ");
}
Console.WriteLine();
}
}
public override double CalculateArea()
{
return Math.PI * radius * radius;
}
public override void Move(int deltaX, int deltaY)
{
center.Move(deltaX, deltaY);
Console.WriteLine($"圆形 {name} 已移动");
}
public double CalculateCircumference()
{
return 2 * Math.PI * radius;
}
}
// 复合图形
public class Group : Drawable
{
private List<Drawable> shapes;
public Group(string name, ConsoleColor color = ConsoleColor.White)
: base(name, color)
{
shapes = new List<Drawable>();
}
public void AddShape(Drawable shape)
{
shapes.Add(shape);
Console.WriteLine($"将 {shape.Name} 添加到组 {name}");
}
public void RemoveShape(Drawable shape)
{
shapes.Remove(shape);
Console.WriteLine($"从组 {name} 移除 {shape.Name}");
}
public override void Draw()
{
Console.WriteLine($"绘制组 {name} (包含 {shapes.Count} 个图形):");
foreach (var shape in shapes)
{
if (shape.IsVisible)
shape.Draw();
}
}
public override double CalculateArea()
{
double totalArea = 0;
foreach (var shape in shapes)
{
totalArea += shape.CalculateArea();
}
return totalArea;
}
public override void Move(int deltaX, int deltaY)
{
Console.WriteLine($"移动组 {name}:");
foreach (var shape in shapes)
{
shape.Move(deltaX, deltaY);
}
}
public override void Show()
{
base.Show();
foreach (var shape in shapes)
{
shape.Show();
}
}
public override void Hide()
{
base.Hide();
foreach (var shape in shapes)
{
shape.Hide();
}
}
}
static void DrawingSystemDemo()
{
Console.WriteLine("=== 图形绘制系统演示 ===");
// 创建基本图形
Point p1 = new Point("P1", 0, 0, ConsoleColor.Red);
Point p2 = new Point("P2", 10, 10, ConsoleColor.Blue);
Line line = new Line("L1", p1, p2, ConsoleColor.Green);
Rectangle rect = new Rectangle("R1", new Point("Corner", 5, 5), 8, 4, ConsoleColor.Yellow);
Circle circle = new Circle("C1", new Point("Center", 15, 15), 3, ConsoleColor.Magenta);
// 创建组合图形
Group house = new Group("House", ConsoleColor.Cyan);
house.AddShape(rect); // 房子主体
house.AddShape(new Rectangle("Roof", new Point("RoofCorner", 4, 1), 10, 4, ConsoleColor.Red));
// 绘制所有图形
List<Drawable> allShapes = new List<Drawable> { p1, p2, line, rect, circle, house };
Console.WriteLine("\n渲染所有图形:");
foreach (var shape in allShapes)
{
shape.Render();
Console.WriteLine($"面积: {shape.CalculateArea():F2}");
Console.WriteLine();
}
// 移动操作
Console.WriteLine("移动操作:");
house.Move(5, 5);
// 显示/隐藏操作
Console.WriteLine("\n隐藏圆形:");
circle.Hide();
Console.WriteLine("\n再次渲染:");
foreach (var shape in allShapes)
{
shape.Render();
}
}示例 2:游戏角色系统
csharp
using System;
using System.Collections.Generic;
// 游戏角色基类
public abstract class GameCharacter
{
protected string name;
protected int level;
protected int health;
protected int maxHealth;
protected int mana;
protected int maxMana;
protected int experience;
public GameCharacter(string name, int level = 1)
{
this.name = name;
this.level = level;
this.maxHealth = CalculateMaxHealth();
this.health = maxHealth;
this.maxMana = CalculateMaxMana();
this.mana = maxMana;
this.experience = 0;
}
// 属性
public string Name => name;
public int Level => level;
public int Health => health;
public int MaxHealth => maxHealth;
public int Mana => mana;
public int MaxMana => maxMana;
public int Experience => experience;
public bool IsAlive => health > 0;
// 抽象方法 - 每个角色类型必须实现
public abstract int CalculateMaxHealth();
public abstract int CalculateMaxMana();
public abstract void LevelUp();
public abstract void UseSpecialAbility(GameCharacter target);
public abstract string GetCharacterType();
// 虚方法 - 可以被重写
public virtual void Attack(GameCharacter target)
{
if (!IsAlive)
{
Console.WriteLine($"{name} 已死亡,无法攻击");
return;
}
int damage = CalculateAttackDamage();
Console.WriteLine($"{name} 攻击 {target.name},造成 {damage} 点伤害");
target.TakeDamage(damage);
}
public virtual int CalculateAttackDamage()
{
return level * 10 + new Random().Next(1, 11); // 基础伤害 + 随机值
}
public virtual void TakeDamage(int damage)
{
health = Math.Max(0, health - damage);
Console.WriteLine($"{name} 受到 {damage} 点伤害,剩余生命值: {health}/{maxHealth}");
if (!IsAlive)
{
Console.WriteLine($"{name} 死亡了!");
}
}
public virtual void Heal(int amount)
{
if (!IsAlive)
{
Console.WriteLine($"{name} 已死亡,无法治疗");
return;
}
int oldHealth = health;
health = Math.Min(maxHealth, health + amount);
int actualHealing = health - oldHealth;
Console.WriteLine($"{name} 恢复了 {actualHealing} 点生命值,当前: {health}/{maxHealth}");
}
public virtual bool UseMana(int amount)
{
if (mana >= amount)
{
mana -= amount;
return true;
}
Console.WriteLine($"{name} 法力值不足");
return false;
}
public virtual void RestoreMana(int amount)
{
mana = Math.Min(maxMana, mana + amount);
}
public void GainExperience(int exp)
{
experience += exp;
Console.WriteLine($"{name} 获得 {exp} 点经验值");
// 检查是否升级
int expNeeded = level * 100;
if (experience >= expNeeded)
{
experience -= expNeeded;
LevelUp();
}
}
public virtual void DisplayStatus()
{
Console.WriteLine($"=== {name} ({GetCharacterType()}) ===");
Console.WriteLine($"等级: {level}");
Console.WriteLine($"生命值: {health}/{maxHealth}");
Console.WriteLine($"法力值: {mana}/{maxMana}");
Console.WriteLine($"经验值: {experience}");
Console.WriteLine($"状态: {(IsAlive ? "存活" : "死亡")}");
}
}
// 战士类
public class Warrior : GameCharacter
{
private int armor;
private int rage;
public Warrior(string name, int level = 1) : base(name, level)
{
armor = level * 5;
rage = 0;
}
public int Armor => armor;
public int Rage => rage;
public override int CalculateMaxHealth()
{
return 100 + level * 20; // 战士生命值较高
}
public override int CalculateMaxMana()
{
return 50 + level * 5; // 战士法力值较低
}
public override void LevelUp()
{
level++;
int oldMaxHealth = maxHealth;
int oldMaxMana = maxMana;
maxHealth = CalculateMaxHealth();
maxMana = CalculateMaxMana();
armor += 5;
health += (maxHealth - oldMaxHealth);
mana += (maxMana - oldMaxMana);
Console.WriteLine($"{name} 升级到 {level} 级!");
Console.WriteLine($"生命值上限增加: {maxHealth - oldMaxHealth}");
Console.WriteLine($"护甲增加: 5");
}
public override int CalculateAttackDamage()
{
int baseDamage = base.CalculateAttackDamage();
int rageDamage = rage * 2; // 怒气增加伤害
return baseDamage + rageDamage;
}
public override void TakeDamage(int damage)
{
int reducedDamage = Math.Max(1, damage - armor); // 护甲减伤
base.TakeDamage(reducedDamage);
// 受伤增加怒气
rage = Math.Min(100, rage + 10);
Console.WriteLine($"{name} 怒气增加到 {rage}");
}
public override void UseSpecialAbility(GameCharacter target)
{
if (!IsAlive || rage < 50)
{
Console.WriteLine($"{name} 无法使用狂暴攻击(需要50点怒气)");
return;
}
rage -= 50;
int damage = CalculateAttackDamage() * 2; // 双倍伤害
Console.WriteLine($"{name} 使用狂暴攻击!");
Console.WriteLine($"{name} 对 {target.name} 造成 {damage} 点伤害");
target.TakeDamage(damage);
}
public override string GetCharacterType()
{
return "战士";
}
public override void DisplayStatus()
{
base.DisplayStatus();
Console.WriteLine($"护甲: {armor}");
Console.WriteLine($"怒气: {rage}/100");
}
}
// 法师类
public class Mage : GameCharacter
{
private int spellPower;
public Mage(string name, int level = 1) : base(name, level)
{
spellPower = level * 8;
}
public int SpellPower => spellPower;
public override int CalculateMaxHealth()
{
return 60 + level * 10; // 法师生命值较低
}
public override int CalculateMaxMana()
{
return 100 + level * 15; // 法师法力值较高
}
public override void LevelUp()
{
level++;
int oldMaxHealth = maxHealth;
int oldMaxMana = maxMana;
maxHealth = CalculateMaxHealth();
maxMana = CalculateMaxMana();
spellPower += 8;
health += (maxHealth - oldMaxHealth);
mana += (maxMana - oldMaxMana);
Console.WriteLine($"{name} 升级到 {level} 级!");
Console.WriteLine($"法术强度增加: 8");
}
public override void Attack(GameCharacter target)
{
if (!UseMana(10))
return;
int damage = level * 8 + spellPower + new Random().Next(1, 16);
Console.WriteLine($"{name} 施放魔法弹攻击 {target.name},造成 {damage} 点伤害");
target.TakeDamage(damage);
}
public override void UseSpecialAbility(GameCharacter target)
{
if (!IsAlive || !UseMana(30))
{
Console.WriteLine($"{name} 无法使用火球术(需要30点法力值)");
return;
}
int damage = spellPower * 3 + level * 15;
Console.WriteLine($"{name} 施放火球术!");
Console.WriteLine($"{name} 对 {target.name} 造成 {damage} 点火焰伤害");
target.TakeDamage(damage);
}
public void CastHeal(GameCharacter target)
{
if (!IsAlive || !UseMana(20))
{
Console.WriteLine($"{name} 无法施放治疗术(需要20点法力值)");
return;
}
int healAmount = spellPower + level * 10;
Console.WriteLine($"{name} 对 {target.name} 施放治疗术");
target.Heal(healAmount);
}
public override string GetCharacterType()
{
return "法师";
}
public override void DisplayStatus()
{
base.DisplayStatus();
Console.WriteLine($"法术强度: {spellPower}");
}
}
// 盗贼类
public class Rogue : GameCharacter
{
private int agility;
private bool isStealthed;
public Rogue(string name, int level = 1) : base(name, level)
{
agility = level * 6;
isStealthed = false;
}
public int Agility => agility;
public bool IsStealthed => isStealthed;
public override int CalculateMaxHealth()
{
return 80 + level * 12;
}
public override int CalculateMaxMana()
{
return 70 + level * 8;
}
public override void LevelUp()
{
level++;
int oldMaxHealth = maxHealth;
int oldMaxMana = maxMana;
maxHealth = CalculateMaxHealth();
maxMana = CalculateMaxMana();
agility += 6;
health += (maxHealth - oldMaxHealth);
mana += (maxMana - oldMaxMana);
Console.WriteLine($"{name} 升级到 {level} 级!");
Console.WriteLine($"敏捷增加: 6");
}
public override int CalculateAttackDamage()
{
int baseDamage = base.CalculateAttackDamage();
int agilityBonus = agility;
int stealthBonus = isStealthed ? baseDamage : 0; // 潜行时双倍伤害
return baseDamage + agilityBonus + stealthBonus;
}
public void Stealth()
{
if (!IsAlive || !UseMana(15))
{
Console.WriteLine($"{name} 无法进入潜行状态(需要15点法力值)");
return;
}
isStealthed = true;
Console.WriteLine($"{name} 进入潜行状态");
}
public override void Attack(GameCharacter target)
{
if (isStealthed)
{
Console.WriteLine($"{name} 从潜行中发动偷袭!");
isStealthed = false; // 攻击后脱离潜行
}
base.Attack(target);
}
public override void UseSpecialAbility(GameCharacter target)
{
if (!IsAlive || !UseMana(25))
{
Console.WriteLine($"{name} 无法使用毒刃攻击(需要25点法力值)");
return;
}
int damage = CalculateAttackDamage();
Console.WriteLine($"{name} 使用毒刃攻击!");
Console.WriteLine($"{name} 对 {target.name} 造成 {damage} 点毒性伤害");
target.TakeDamage(damage);
// 毒性效果:持续伤害
Console.WriteLine($"{target.name} 中毒了,将在接下来受到持续伤害");
}
public override string GetCharacterType()
{
return "盗贼";
}
public override void DisplayStatus()
{
base.DisplayStatus();
Console.WriteLine($"敏捷: {agility}");
Console.WriteLine($"潜行状态: {(isStealthed ? "是" : "否")}");
}
}
static void GameCharacterDemo()
{
Console.WriteLine("=== 游戏角色系统演示 ===");
// 创建不同类型的角色
Warrior warrior = new Warrior("勇敢的战士", 5);
Mage mage = new Mage("智慧法师", 4);
Rogue rogue = new Rogue("影子刺客", 4);
// 显示初始状态
Console.WriteLine("初始角色状态:");
warrior.DisplayStatus();
Console.WriteLine();
mage.DisplayStatus();
Console.WriteLine();
rogue.DisplayStatus();
Console.WriteLine();
// 战斗演示
Console.WriteLine("=== 战斗开始 ===");
// 盗贼进入潜行
rogue.Stealth();
// 第一轮攻击
Console.WriteLine("\n第一轮:");
warrior.Attack(mage);
mage.CastHeal(mage); // 法师自我治疗
rogue.Attack(warrior); // 潜行偷袭
// 第二轮攻击
Console.WriteLine("\n第二轮:");
warrior.UseSpecialAbility(rogue); // 狂暴攻击
mage.UseSpecialAbility(warrior); // 火球术
rogue.UseSpecialAbility(mage); // 毒刃攻击
// 显示战斗后状态
Console.WriteLine("\n战斗后状态:");
warrior.DisplayStatus();
Console.WriteLine();
mage.DisplayStatus();
Console.WriteLine();
rogue.DisplayStatus();
// 经验值和升级
Console.WriteLine("\n=== 获得经验值 ===");
warrior.GainExperience(150);
mage.GainExperience(200);
rogue.GainExperience(180);
}本章小结
本章详细介绍了 C# 中的继承:
关键要点:
- 继承语法:class 派生类 : 基类
- base 关键字:调用基类构造函数和方法
- 方法重写:virtual/override 实现多态性
- 方法隐藏:new 关键字隐藏基类方法
- 抽象类:abstract 类和方法强制派生类实现
继承的好处:
- 代码重用:避免重复编写相同的代码
- 扩展性:在现有类基础上添加新功能
- 多态性:统一接口处理不同类型的对象
- 维护性:修改基类影响所有派生类
设计原则:
- 里氏替换原则:派生类对象应该能够替换基类对象
- 开闭原则:对扩展开放,对修改关闭
- 单一职责:每个类应该只有一个改变的理由
最佳实践:
- 合理使用 virtual/override 实现多态
- 在构造函数中正确调用 base()
- 使用 sealed 防止不必要的继承
- 抽象类用于定义公共接口和部分实现
- 避免过深的继承层次
继承 vs 组合:
- 继承表示"是一个"(is-a)关系
- 组合表示"有一个"(has-a)关系
- 优先考虑组合,谨慎使用继承
下一步: 在下一章中,我们将学习多态,深入理解面向对象编程的第三个核心特性。