多态(Polymorphism)是 C# 面向对象编程(OOP)的三大特性之一:
- 封装(Encapsulation)
- 继承(Inheritance)
- 多态(Polymorphism)
多态的核心思想:
同一个行为,在不同对象中表现出不同的结果。
简单理解:
父类引用指向子类对象,调用同一个方法时,根据实际对象类型执行不同代码。
例如:
cs
Animal animal;
animal = new Dog();
animal.Speak(); // 输出:汪汪
animal = new Cat();
animal.Speak(); // 输出:喵喵
虽然变量类型都是 Animal,但是执行结果不同,这就是多态。
一、多态的作用
多态主要解决:
1. 提高代码扩展性
没有多态:
cs
Dog dog = new Dog();
dog.Speak();
Cat cat = new Cat();
cat.Speak();
以后增加:
Bird bird = new Bird();
bird.Speak();
需要不断修改代码。
使用多态:
cs
Animal animal;
animal = new Dog();
animal.Speak();
animal = new Cat();
animal.Speak();
animal = new Bird();
animal.Speak();
以后增加动物,只需要继承 Animal。
二、C# 多态的实现方式
C# 中主要有三种多态:
| 类型 | 实现方式 |
|---|---|
| 编译时多态 | 方法重载(Overload) |
| 运行时多态 | 虚方法(virtual/override) |
| 接口多态 | interface |
三、编译时多态(方法重载)
1. 什么是方法重载?
同一个类中:
- 方法名相同
- 参数列表不同
例如:
cs
class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
public double Add(double a, double b)
{
return a + b;
}
public int Add(int a, int b, int c)
{
return a + b + c;
}
}
调用:
cs
Calculator c = new Calculator();
Console.WriteLine(c.Add(1,2));
Console.WriteLine(c.Add(1.5,2.5));
Console.WriteLine(c.Add(1,2,3));
输出:
3
4
6
为什么叫编译时多态?
因为:
编译器根据参数类型决定调用哪个方法。
例如:
Add(10,20)
编译器看到:
int,int
选择:
Add(int,int)
四、运行时多态(重点)
运行时多态是 C# 最常用的多态形式。
依靠:
- virtual
- override
- base
实现。
1. virtual(虚方法)
父类定义:
cs
class Animal
{
public virtual void Speak()
{
Console.WriteLine("动物叫");
}
}
virtual 表示:
这个方法允许子类重新实现。
2. override(重写)
子类:
cs
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("汪汪");
}
}
另一个子类:
cs
class Cat : Animal
{
public override void Speak()
{
Console.WriteLine("喵喵");
}
}
3. 使用父类引用调用
cs
Animal a;
a = new Dog();
a.Speak();
a = new Cat();
a.Speak();
输出:
汪汪
喵喵
这里发生了什么?
变量:
Animal a;
编译类型:
Animal
实际对象:
第一次:
Dog
第二次:
Cat
运行时根据对象真实类型决定调用哪个方法。
这就是:
动态绑定(Dynamic Binding)
五、完整运行时多态案例
假设开发一个游戏:
所有角色都有攻击方法:
cs
class Role
{
public virtual void Attack()
{
Console.WriteLine("普通攻击");
}
}
战士:
cs
class Warrior : Role
{
public override void Attack()
{
Console.WriteLine("挥剑攻击");
}
}
法师:
cs
class Mage : Role
{
public override void Attack()
{
Console.WriteLine("释放魔法");
}
}
弓箭手:
cs
class Archer : Role
{
public override void Attack()
{
Console.WriteLine("射箭攻击");
}
}
统一调用:
cs
List<Role> roles = new List<Role>()
{
new Warrior(),
new Mage(),
new Archer()
};
foreach(Role role in roles)
{
role.Attack();
}
输出:
挥剑攻击
释放魔法
射箭攻击
优势:
以后增加:
cs
class Assassin : Role
{
public override void Attack()
{
Console.WriteLine("暗杀");
}
}
原代码:
cs
foreach(Role role in roles)
{
role.Attack();
}
无需修改。
这就是:
开闭原则(Open Closed Principle)
六、隐藏方法 new 与 override 区别
很多初学者容易混淆:
override
真正实现多态:
cs
class Dog:Animal
{
public override void Speak()
{
Console.WriteLine("狗叫");
}
}
调用:
cs
Animal a=new Dog();
a.Speak();
输出:
狗叫
new 隐藏方法
cs
class Dog:Animal
{
public new void Speak()
{
Console.WriteLine("狗叫");
}
}
调用:
cs
Animal a=new Dog();
a.Speak();
输出:
动物叫
因为:
new 不产生多态,只隐藏父类方法。
七、抽象类实现多态
如果父类没有具体实现,可以使用:
abstract
父类:
cs
abstract class Shape
{
public abstract double Area();
}
圆:
cs
class Circle : Shape
{
public double Radius;
public override double Area()
{
return Math.PI * Radius * Radius;
}
}
矩形:
cs
class Rectangle : Shape
{
public double Width;
public double Height;
public override double Area()
{
return Width * Height;
}
}
调用:
cs
Shape s;
s=new Circle();
Console.WriteLine(s.Area());
s=new Rectangle();
Console.WriteLine(s.Area());
八、接口实现多态
接口是 C# 中非常重要的多态方式。
定义:
cs
interface IAnimal
{
void Speak();
}
实现:
cs
class Dog:IAnimal
{
public void Speak()
{
Console.WriteLine("汪汪");
}
}
cs
class Cat:IAnimal
{
public void Speak()
{
Console.WriteLine("喵喵");
}
}
调用:
cs
IAnimal animal;
animal=new Dog();
animal.Speak();
animal=new Cat();
animal.Speak();
输出:
汪汪
喵喵
九、virtual、abstract、interface区别
| 特性 | virtual | abstract | interface |
|---|---|---|---|
| 是否有实现 | 可以有 | 没有 | 没有 |
| 子类是否必须重写 | 否 | 必须 | 必须 |
| 所在位置 | 普通类 | 抽象类 | 接口 |
| 支持多继承 | 否 | 否 | 是 |
| 用途 | 扩展已有行为 | 定义规范 | 定义能力 |
十、多态的底层原理(简单理解)
例如:
cs
Animal a = new Dog();
a.Speak();
内存:
a
|
|
+---- Dog对象
|
+ Speak()
运行时:
- 找到对象真实类型
- 查看虚方法表(Virtual Table)
- 调用 Dog 的 Speak()
因此:
Animal
|
|
Dog
可以执行:
Dog.Speak()
十一、多态常见应用场景
1. 游戏开发
角色:
Character
├── Warrior
├── Mage
└── Archer
统一:
character.Attack();
2. 支付系统
Payment
|
+-- Alipay
|
+-- WeChatPay
|
+-- BankPay
调用:
payment.Pay();
3. 数据库访问
Database
|
+-- MySQL
|
+-- SQLServer
|
+-- Oracle
统一:
database.Connect();
十二、多态设计原则
优秀的多态设计:
面向抽象编程
不要:
Dog dog=new Dog();
推荐:
Animal animal=new Dog();
少使用类型判断
不推荐:
cs
if(animal is Dog)
{
}
else if(animal is Cat)
{
}
应该:
animal.Speak();
让对象自己处理行为。
十三、总结
| 概念 | 关键字 | 说明 |
|---|---|---|
| 方法重载 | 无 | 编译时多态 |
| 虚方法 | virtual | 允许重写 |
| 方法重写 | override | 实现运行时多态 |
| 抽象方法 | abstract | 强制子类实现 |
| 接口 | interface | 规范多态 |
一句话总结:
C# 多态就是通过父类或接口引用指向不同子类对象,让同一个方法调用产生不同的行为,从而提高程序的扩展性和可维护性。