-
多态:方法重写与接口多态
《C#从入门到精通:实例驱动学习指南》
多态:方法重写与接口多态
-
多态的核心概念
多态(Polymorphism)是面向对象编程(OOP)三大特性之一,定义为同一行为的不同表现形式。核心价值在于解耦代码依赖,让程序能灵活处理不同类型的对象,提高扩展性和可维护性。
多态的实现方式主要有两种:
方法重写多态:基于类继承,通过virtual/override关键字实现;
接口多态:基于接口实现,通过多个类实vb.net教程C#教程python教程SQL教程access 2010教程现同一接口达成。 -
方法重写多态(基于类继承)
方法重写多态是子类重写父类虚方法,通过父类引用指向子类实例,调用方法时自动执行子类的实现。
2.1 前置知识回顾
虚方法:父类中用virtual修饰的方法,允许子类重写;
重写方法:子类中用override修饰的方法,覆盖父类虚方法的实现;
多态调用:父类类型的引用指向子类实例,调用方法时执行子类的重写逻辑。
2.2 实例代码及逐行讲解
csharp
using System;
// 父类:Animal(定义虚方法)
public class Animal
{
public string Name { get; set; }
// 虚方法:允许子类重写
public virtual void Eat()
{
Console.WriteLine($"{Name}正在进食");
}
public Animal(string name)
{
Name = name;
}
}
// 子类:Dog(重写Eat方法)
public class Dog : Animal
{
public Dog(string name) : base(name) {}
// 重写父类虚方法
public override void Eat()
{
Console.WriteLine($"{Name}(狗)啃骨头");
}
}
// 子类:Cat(重写Eat方法)
public class Cat : Animal
{
public Cat(string name) : base(name) {}
// 重写父类虚方法
public override void Eat()
{
Console.WriteLine($"{Name}(猫)吃鱼");
}
}
// 测试类
class Program
{
static void Main(string[] args)
{
// 父类引用指向子类实例(多态核心)
Animal[] animals = new Animal[]
{
new Dog("旺财"),
new Cat("咪咪"),
new Animal("未知动物")
};
// 循环调用Eat方法,自动执行对应子类的实现
foreach (var animal in animals)
{
animal.Eat();
}
}
}
逐行讲解:
1.Animal类:定义virtual void Eat(),允许子类重写;
2.Dog/Cat类:用override重写Eat,实现各自的进食逻辑;
3.Main方法:
o创建Animal类型数组,存储Dog、Cat、Animal实例;
o循环调用Eat():根据实例的实际类型执行对应逻辑(如Dog实例执行Dog.Eat())。
输出结果:
旺财(狗)啃骨头
咪咪(猫)吃鱼
未知动物正在进食
-
接口多态(基于接口实现)
接口多态是多个类实现同一接口,通过接口引用指向不同类的实例,调用方法时自动执行对应类的实现。解决了C#单继承的限制,是更灵活的多态方式。
3.1 接口的定义
接口是行为契约,仅定义方法签名(无实现),强制实现类必须提供方法的具体逻辑。语法如下:
csharp
public interface IEatable
{
void Eat(); // 仅定义方法签名,无实现
}
3.2 实例代码及逐行讲解
csharp
using System;
// 接口:IEatable(定义进食行为契约)
public interface IEatable
{
void Eat();
}
// 类1:Dog实现IEatable
public class Dog : IEatable
{
public void Eat() // 必须实现接口方法
{
Console.WriteLine("狗啃骨头");
}
}
// 类2:Cat实现IEatable
public class Cat : IEatable
{
public void Eat()
{
Console.WriteLine("猫吃鱼");
}
}
// 类3:Bird实现IEatable
public class Bird : IEatable
{
public void Eat()
{
Console.WriteLine("鸟啄种子");
}
}
// 测试类
class Program
{
static void Main(string[] args)
{
// 接口引用指向不同类的实例(接口多态核心)
IEatable[] eatables = new IEatable[]
{
new Dog(),
new Cat(),
new Bird()
};
// 循环调用Eat方法,自动执行对应类的实现
foreach (var eatable in eatables)
{
eatable.Eat();
}
}
}
逐行讲解:
1.IEatable接口:定义Eat()方法签名,作为进食行为的契约;
2.Dog/Cat/Bird类:实现IEatable接口,提供各自的Eat()逻辑;
3.Main方法:
o创建IEatable类型数组,存储不同类的实例;
o循环调用Eat():根据实例的实际类型执行对应逻辑(如Bird实例执行Bird.Eat())。
输出结果:
狗啃骨头
猫吃鱼
鸟啄种子
-
基础知识拓展
4.1 多态的实现原理(虚方法表VMT)
C#通过虚方法表(Virtual Method Table,VMT)实现多态:
每个包含虚方法的类都有一个VMT,存储虚方法的内存地址;
子类重写虚方法时,会替换VMT中对应方法的地址;
调用方法时,程序通过实例的VMT找到对应方法的地址,执行子类实现。
4.2 方法重写vs方法隐藏
特性 方法重写(override) 方法隐藏(new)
关键字 virtual+override new
父类方法要求 必须是虚方法 无限制
调用逻辑 按实例类型执行 按引用类型执行
示例:
csharp
Animal animal = new Dog();
animal.Eat(); // 重写:执行Dog.Eat();隐藏:执行Animal.Eat()
4.3 接口多态的优势
突破单继承限制:一个类可实现多个接口,同时拥有多种行为;
解耦更强:接口仅定义契约,不依赖具体实现;
扩展性更好:新增类只需实现接口,无需修改现有代码(符合开闭原则)。
4.4 抽象类vs接口的选择
| 场景 | 选择抽象类 | 选择接口 |
|---|---|---|
| 需要共享代码逻辑 | ✅ | ❌ |
| 仅定义行为契约 | ❌ | ✅ |
| 子类需继承多个行为 | ❌(单继承) | ✅(多实现) |
| 需要静态成员或构造函数 | ✅ | ❌(接口无静态/构造) |
-
总结
多态是C#中实现灵活代码的核心手段:
方法重写多态:适合有继承关系的类,通过virtual/override实现;
接口多态:适合无继承关系的类,通过接口实现,更灵活;
核心价值:让程序能以统一方式处理不同类型的对象,降低耦合,提高扩展性。
下一章将讲解泛型,进一步提升代码的复用性。
练习:定义IFlyable接口,让Bird、Plane类实现该接口,编写多态调用示例。
csharp
// 接口定义
public interface IFlyable { void Fly(); }
// Bird类实现
public class Bird : IFlyable { public void Fly() => Console.WriteLine("鸟飞"); }
// Plane类实现
public class Plane : IFlyable { public void Fly() => Console.WriteLine("飞机飞"); }
(测试代码请自行补充)
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49368.html
最新更新
接口(Interface):行为规范
多态:方法重写与接口多态
继承:代码复用与扩展
封装:访问修饰符与属性(Property)
构造函数与析构函数
类的定义与对象的创建
跳转语句:break、continue与return
循环语句:for、while与foreach
第二十四章:工作流高级逻辑
第二十三章:工作流基础搭建
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比










