Skip to content

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)关系
  • 优先考虑组合,谨慎使用继承

下一步: 在下一章中,我们将学习多态,深入理解面向对象编程的第三个核心特性。

延伸阅读

本站内容仅供学习和研究使用。