C# 多态性详解

多态(Polymorphism)是 C# 面向对象编程(OOP)的三大特性之一

  1. 封装(Encapsulation)
  2. 继承(Inheritance)
  3. 多态(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()

运行时:

  1. 找到对象真实类型
  2. 查看虚方法表(Virtual Table)
  3. 调用 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# 多态就是通过父类或接口引用指向不同子类对象,让同一个方法调用产生不同的行为,从而提高程序的扩展性和可维护性。

相关推荐
逝水无殇1 小时前
C# 继承(Inheritance)详解
开发语言·后端·c#
多加点辣也没关系1 小时前
JavaScript|第6章:流程控制语句
开发语言·前端·javascript
用户938515635071 小时前
手写迷你 Cursor 终端:深入 Node.js child_process 的 spawn 核心实现
javascript·后端
阿新聊ai1 小时前
Claude Code 为什么总不懂你的项目?缺一张「项目地图」
前端·后端·面试
用户40966601317511 小时前
Spring Boot 中 Filter、Interceptor、AOP 到底谁先执行?
后端
暗冰ཏོ1 小时前
Spring Boot + Vue3 订单支付模块技术实现:支付单、回调验签、幂等处理与余额扣减
前端·spring boot·后端·vue·微信支付·支付宝支付
Csvn1 小时前
Python 开发技巧 · 类型注解进阶 —— 从 `TypeVar` 到 `Protocol`,让类型检查真正帮你抓 bug
后端·python
foundbug9991 小时前
Polar Code 编解码 MATLAB 实现
开发语言·算法·matlab
爷_2 小时前
AI Coding Agent 沙箱的设计原理解析
前端·人工智能·后端