多态
C#中的多态是指一个实体可以有多种形态。它主要体现在:
- 继承
子类可以重写父类的方法,实现不同的功能,这就是多态性。 - 接口
实现同一个接口的不同类,对同一个方法可以有不同实现。 - 虚方法
使用virtual和override关键字实现方法的重写。 - 抽象类和接口
抽象类和接口定义标准但不实现具体行为,留给派生类实现。 - 多态使用
父类引用可以指向子类对象,在调用方法时自动选择子类版本。 - 只能访问父类接口
通过父类引用只能访问父类中的成员,不知道具体子类。 - 动态绑定
调用时根据对象实际类型选择方法实现版本,这是多态的关键。
所以C#多态主要通过继承、接口和虚方法实现子类重写,利用父类引用来调用方法产生不同效果。它可以提高程序的可扩展性和重用性。
虚方法实现多态
虚方法(Virtual Method)是一种允许子类重写的方法,虚方法用于建立基类和子类之间的多态性关系。
在基类中,可以使用 virtual 关键字来定义一个虚方法。虚方法可以被子类重写,子类可以通过 override 关键字来重写基类中的虚方法。
常见的虚方法:ToString() Equals()
// 基类
public class Animal
{
public virtual void Eat()
{
Console.WriteLine("Animal is eating...");
}
}
// 派生类
public class Dog : Animal
{
public override void Eat()
{
Console.WriteLine("Dog is eating dog food...");
}
}
public class Cat : Animal
{
public override void Eat()
{
Console.WriteLine("Cat is eating fish...");
}
}
class Program
{
static void Main(string[] args)
{
Animal dog = new Dog();
Animal cat = new Cat();
dog.Eat(); // 输出:Dog is eating dog food...
cat.Eat(); // 输出:Cat is eating fish...
Animal animal = new Animal();
animal.Eat(); // 输出:Animal is eating...
}
}
抽象类实现多态
使用抽象类实现多态的主要特征是:
抽象类中定义抽象方法,不提供实现细节。
派生类必须实现抽象基类中的所有抽象方法。
派生类可以自由实现方法的细节。
// 定义一个简单的形状接口
public abstract class Shape
{
public abstract void Draw();
}
// 具体圆形类
public class Circle : Shape
{
public override void Draw()
{
Console.WriteLine("Drawing a circle");
// 实现圆的绘制逻辑
DrawCircle();
}
private void DrawCircle()
{
// 实际绘制圆的代码
}
}
// 具体矩形类
public class Rectangle : Shape
{
public override void Draw()
{
Console.WriteLine("Drawing a rectangle");
// 实现矩形的绘制逻辑
DrawRectangle();
}
private void DrawRectangle()
{
// 实际绘制矩形的代码
}
}
class Program
{
public static void Main(string[] args)
{
List<Shape> shapes = new List<Shape>();
shapes.Add(new Circle());
shapes.Add(new Rectangle());
foreach (Shape shape in shapes)
{
shape.Draw();
}
}
}
虚方法和抽象类实现多态的对比
- 如果父类中的方法有默认的实现,并且父类需要被实例化,这时可以考虑将父类定义成一个普通类,用虚方法来实现多态。
- 如果父类中的方法没有默认实现,父类也不需要被实例化,则可以将该类定义为抽象类。
接口
接口是一种规范,只要一个类实现了一个接口,这个类就必须实现这个接口中所有的成员。
基本语法:interface关键字声明接口,接口中可以有属性、方法,没有实现
接口所有成员默认为public
接口的名称通常以“I”开头,如IList
[访问修饰符] interface 接口名
{
// 接口成员定义
}
public interface IBusiness
{
void GetMoney();
}
public interface IGovernment
{
void GetPower();
}
如果一个类即继承了类又实现了接口,那么类必须写在前面。一个类只能继承一个父类,但可以实现多个接口
public interface IBusiness: All
{
void GetMoney();
}
public interface IGovernment: All
{
void GetPower();
}
public interface All
{
void EveryThing();
int Every
{
get; set;
}
double Much { get; }
}
接口和抽象类的区别
- 实现方式:接口只能声明方法,属性和事件的签名,不能有实现,而抽象类可以包含抽象方法和具体方法。
- 实现限制:一个类可以实现多个接口,但只能继承一个抽象类。
- 构造函数:抽象类可以有构造函数,而接口不能有构造函数。
- 访问修饰符:接口中的方法和属性默认为公共的,可以为public、internal、protected,而抽象类可以有任何访问修饰符。
- 用途:接口用于定义一组必须实现的方法和属性,以确保类实现了特定的行为。抽象类用于定义一个模板类,其中包含了一些通用方法和属性,需要在派生类中实现。