C# 继承
本章将详细介绍 C# 中的继承机制,包括类继承、构造函数调用、方法重写等。
继承的基本概念
什么是继承?
继承是面向对象编程的核心特性之一,它允许我们基于已有的类创建新类,新类可以继承已有类的属性和方法。
┌─────────────────────┐
│ 基类 (Parent) │
│ ────────────────── │
│ + Name │
│ + Age │
│ + Eat() │
│ + Sleep() │
└─────────────────────┘
▲
│ 继承
┌─────────────────────┐
│ 派生类 (Child) │
│ ────────────────── │
│ + Name │ ← 继承
│ + Age │ ← 继承
│ + Eat() │ ← 继承
│ + Sleep() │ ← 继承
│ + Study() │ ← 新增
│ + Exam() │ ← 新增
└─────────────────────┘
继承的实现
单继承
// 基类
class Animal
{
public string Name { get; set; }
public int Age { get; set; }
public Animal(string name, int age)
{
Name = name;
Age = age;
}
public void Eat()
{
Console.WriteLine($"{Name} 正在吃东西");
}
public void Sleep()
{
Console.WriteLine($"{Name} 正在睡觉");
}
}
// 派生类
class Dog : Animal
{
public string Breed { get; set; }
public Dog(string name, int age, string breed)
: base(name, age) // 调用基类构造函数
{
Breed = breed;
}
// 新增方法
public void Bark()
{
Console.WriteLine($"{Name} 正在汪汪叫");
}
// 重写基类方法
public override void Eat()
{
Console.WriteLine($"{Name} 正在吃狗粮");
}
}
// 使用
Dog dog = new Dog("旺财", 3, "金毛");
dog.Eat(); // 调用重写后的方法
dog.Sleep(); // 继承自基类的方法
dog.Bark(); // 派生类自己的方法
多层继承
// 爷爷类
class LivingThing
{
public void Breathe()
{
Console.WriteLine("呼吸");
}
}
// 父类
class Animal : LivingThing
{
public void Eat()
{
Console.WriteLine("吃东西");
}
}
// 子类
class Dog : Animal
{
public void Bark()
{
Console.WriteLine("汪汪叫");
}
}
// 使用
Dog dog = new Dog();
dog.Breathe(); // 继承自爷爷类
dog.Eat(); // 继承自父类
dog.Bark(); // 自己独有的
多继承的限制
C# 不支持直接多继承(一个类继承多个类),但可以通过接口实现多继承的效果:
// 不允许这样的继承
// class Student : Person, Teacher // 错误!
// 可以实现多个接口
class Student : Person, IStudy, IWork
{
public void Study() { }
public void Work() { }
}
基类构造函数
使用 base 关键字
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
class Student : Person
{
public string School { get; set; }
// 显式调用基类构造函数
public Student(string name, int age, string school)
: base(name, age)
{
School = school;
}
}
默认基类构造函数
class Base
{
public Base()
{
Console.WriteLine("Base 构造函数");
}
}
class Derived : Base
{
public Derived()
{
// 隐式调用 base()
Console.WriteLine("Derived 构造函数");
}
}
new Derived();
// 输出:
// Base 构造函数
// Derived 构造函数
方法重写
virtual 和 override
class Shape
{
// 虚方法:可以在派生类中重写
public virtual double Area()
{
return 0;
}
public virtual void Draw()
{
Console.WriteLine("绘制图形");
}
}
class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public Rectangle(double width, double height)
{
Width = width;
Height = height;
}
// 重写虚方法
public override double Area() => Width * Height;
public override void Draw()
{
Console.WriteLine($"绘制矩形: {Width}x{Height}");
}
}
class Circle : Shape
{
public double Radius { get; set; }
public Circle(double radius)
{
Radius = radius;
}
public override double Area() => Math.PI * Radius * Radius;
public override void Draw()
{
Console.WriteLine($"绘制圆: 半径={Radius}");
}
}
new 关键字(隐藏方法)
class Base
{
public void Method()
{
Console.WriteLine("Base Method");
}
}
class Derived : Base
{
// 使用 new 隐藏基类方法
public new void Method()
{
Console.WriteLine("Derived Method");
}
}
Base b = new Derived();
b.Method(); // 输出: Base Method(调用的是基类方法)
Derived d = new Derived();
d.Method(); // 输出: Derived Method
base 关键字的使用
class Animal
{
public virtual void Speak()
{
Console.WriteLine("动物叫声");
}
}
class Cat : Animal
{
public override void Speak()
{
// 调用基类的实现
base.Speak();
// 然后添加自己的逻辑
Console.WriteLine("喵喵喵");
}
}
Cat cat = new Cat();
cat.Speak();
/*
输出:
动物叫声
喵喵喵
*/
抽象类
abstract 关键字
// 抽象类:不能实例化
abstract class Animal
{
public string Name { get; set; }
// 抽象方法:没有实现,必须在派生类中重写
public abstract void Speak();
// 抽象属性
public abstract int Age { get; set; }
// 抽象类可以有具体方法
public void Sleep()
{
Console.WriteLine($"{Name} 正在睡觉");
}
}
class Dog : Animal
{
public override int Age { get; set; }
public override void Speak()
{
Console.WriteLine($"{Name} 说: 汪汪");
}
}
// 使用
Animal animal = new Dog { Name = "旺财", Age = 3 };
animal.Speak();
animal.Sleep();
// animal 不能直接 new Animal()
抽象类示例
abstract class Vehicle
{
public string Brand { get; set; }
public string Model { get; set; }
// 抽象方法
public abstract void Start();
public abstract void Stop();
// 具体方法
public void DisplayInfo()
{
Console.WriteLine($"{Brand} - {Model}");
}
}
class Car : Vehicle
{
public override void Start()
{
Console.WriteLine("汽车启动");
}
public override void Stop()
{
Console.WriteLine("汽车停止");
}
}
class Motorcycle : Vehicle
{
public override void Start()
{
Console.WriteLine("摩托车启动");
}
public override void Stop()
{
Console.WriteLine("摩托车停止");
}
}
访问基类成员
protected 修饰符
class Person
{
protected string name = "张三"; // 受保护成员
private int age = 20; // 私有成员
}
class Student : Person
{
public void Print()
{
Console.WriteLine(name); // 可以访问 protected 成员
// Console.WriteLine(age); // 错误!不能访问 private 成员
}
}
继承与组合
组合 vs 继承
// 继承:is-a 关系
class Animal { }
class Dog : Animal { } // Dog is an Animal
// 组合:has-a 关系
class Engine { }
class Car
{
private Engine _engine; // Car has an Engine
public Car(Engine engine)
{
_engine = engine;
}
}
优先使用组合
// 不推荐的继承用法
class CoffeeMachine
{
public void MakeCoffee() { }
}
class AdvancedCoffeeMachine : CoffeeMachine // 不恰当
{
public void MakeTea() { }
}
// 更好的方式:组合
class CoffeeMachine
{
public void MakeCoffee() { }
}
class AdvancedAppliance
{
private CoffeeMachine _coffeeMachine = new CoffeeMachine();
public void MakeCoffee() => _coffeeMachine.MakeCoffee();
public void MakeTea() { /* 新的功能 */ }
}
多态
向上转型
Animal animal = new Dog("旺财", 3);
animal.Eat(); // 调用 Dog 的方法(如果重写了)
// animal.Bark(); // 错误!Animal 类型看不到 Dog 的方法
向下转型
Animal animal = new Dog("旺财", 3);
// 安全检查
if (animal is Dog dog)
{
dog.Bark(); // 可以使用 Dog 的方法
}
// 使用 as
Dog dog2 = animal as Dog;
if (dog2 != null)
{
dog2.Bark();
}
多态的应用
class Payment
{
public virtual void Process()
{
Console.WriteLine("处理支付");
}
}
class WeChatPay : Payment
{
public override void Process()
{
Console.WriteLine("微信支付");
}
}
class AliPay : Payment
{
public override void Process()
{
Console.WriteLine("支付宝");
}
}
// 多态调用
Payment[] payments = {
new WeChatPay(),
new AliPay(),
new Payment()
};
foreach (var p in payments)
{
p.Process(); // 调用各自的重写方法
}
小结
- 单继承:C# 只允许单继承,可以用接口弥补
- base 关键字:调用基类构造函数和方法
- virtual/override:实现运行时多态
- new 关键字:隐藏基类方法
- 抽象类:包含抽象成员的类,不能实例化
- 组合优先:优先使用组合而非继承
练习
- 创建一个基类
Shape,派生出Circle、Rectangle、Triangle - 使用抽象类实现一个员工管理系统
- 实现一个多态的支付系统(支持不同支付方式)
- 理解组合和继承的使用场景