翼度科技»论坛 编程开发 .net 查看内容

C#多态性学习,虚方法、抽象方法、接口等用法举例

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
1. 多态性定义

  C#中的多态性是OOP(面向对象编程)的一个基本概念,它允许一个对象在不同情况下表现出不同的行为,以增强代码的可重用性和灵活性。
  根据网上的教程,我们得知C#多态性分为两类,静态和动态。但实际上,C#没有严格的静态和动态多态性的分法。之所以这么分,还是为了我们便于理解,我们沿用这个思维来大概分类:
采用函数重载或运算符重载方法的,属于静态多态性;
采用虚方法、抽象方法、接口等方式,属于动态多态性。
拓展:在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。什么意思呢?
在静态语言中,许多多态性的特性可以在编译时确定,编译器可以根据数据类型的信息来确定方法的调用方式。
而在动态语言中,数据类型的确定通常是在运行时进行的,这种行为被称为动态多态性。
2. 函数重载示例

  函数重载是指在同一个类中,定义多个方法,它们的方法名相同,但是参数类型、参数数量、参数顺序不同。以下是一个函数重载的例子:
  1. public class Calculator
  2. {
  3.     public int Add(int a, int b)
  4.     {
  5.         return a + b;
  6.     }
  7.     public int Add(int a, int b, int c)
  8.     {
  9.         return a + b + c;
  10.     }
  11.     public float Add(float a, float b)
  12.     {
  13.         return a + b;
  14.     }
  15.     public double Add(double a, double b)
  16.     {
  17.         return a + b;
  18.     }
  19. }
复制代码
  在这个例子中,Calculator类定义了4个Add()方法,它们的方法名相同但是参数列表不同(分别有2个整型参数、3个整型参数、2个浮点型参数、2个双精度浮点型参数)。这些方法根据声明的参数类型和数量而得到不同的签名,因此构成函数重载,当调用Add()方法时,编译器会根据参数的类型和数量来选择正确的方法重载进行调用。
3. 虚方法示例

  虚方法和重写(override)方法:在父类中声明一个虚方法,子类可以重写该方法并实现自己的行为。在运行时,程序根据对象的实际类型调用相应的方法。这种方式也称为“消除静态绑定”。
注意事项:虚方法是使用关键字 virtual 声明的。同时继承类中的重写虚函数需要声明关键字 override 。下面是一个示例:
  1. // 定义一个Animal类和其子类
  2. class Animal
  3. {
  4.     public virtual void Speak()
  5.     {
  6.         Console.WriteLine("I am an animal.");
  7.     }
  8. }
  9. class Dog : Animal
  10. {
  11.     public override void Speak()
  12.     {
  13.         Console.WriteLine("Woof!");
  14.     }
  15. }
  16. class Cat : Animal
  17. {
  18.     public override void Speak()
  19.     {
  20.         Console.WriteLine("Meow!");
  21.     }
  22. }
  23. // 示例程序
  24. class Program
  25. {
  26.     static void Main(string[] args)
  27.     {
  28.         Animal[] animals = new Animal[2];
  29.         animals[0] = new Dog();
  30.         animals[1] = new Cat();
  31.         foreach (Animal animal in animals)
  32.         {
  33.             animal.Speak();
  34.         }
  35.         Console.ReadKey();
  36.     }
  37. }
复制代码
  在这个例子中,Animal类中声明了一个虚方法Speak(),它的子类 Dog 和 Cat 分别对该方法进行了重写。在Main 方法中,创建了一个 Animal 数组,其中存放了 Dog 和 Cat 的实例。在foreach循环中,程序根据实际对象类型调用了不同的Speak()方法,实现了多态性的效果。
小拓展:关键字重写 override 与覆盖 new 较为容易搞混,有关两者区别可移步:C#中重写(override)及覆盖(new)的区别详解
4. 抽象方法示例

  抽象方法是在抽象类中定义的,它没有具体实现的代码,而只是定义了方法的名称、参数和返回值类型等信息。抽象方法必须在子类中进行完整的实现,否则子类本身也必须定义为抽象类。使用abstract关键字来定义抽象类和抽象方法。
下面的示例演示了如何定义并使用抽象方法:
  1. abstract class Shape
  2. {
  3.   public abstract double Area(); // 定义抽象方法Area()
  4. }
  5. // 派生类Rectangle继承抽象类Shape
  6. class Rectangle : Shape  
  7. {
  8.   double width, height;
  9.   public Rectangle(double w, double h)
  10.   {
  11.     width = w;
  12.     height = h;
  13.   }
  14.   
  15.   public override double Area() // 实现抽象方法Area()
  16.   {
  17.     return width * height;
  18.   }
  19. }
  20. class Triangle : Shape  
  21. {
  22.   double baseValue, height;
  23.   public Triangle(double bv, double h)
  24.   {
  25.     baseValue = bv;
  26.     height = h;
  27.   }
  28.   
  29.   public override double Area() // 实现抽象方法Area()
  30.   {
  31.     return baseValue * height * 0.5;
  32.   }
  33. }
  34. class Program
  35. {
  36.   static void Main(string[] args)
  37.   {
  38.     Rectangle r = new Rectangle(5, 8);
  39.     Console.WriteLine("矩形的面积 = {0}", r.Area());
  40.     Triangle t = new Triangle(5, 8);
  41.     Console.WriteLine("三角形的面积 = {0}", t.Area());
  42.   }
  43. }
复制代码
  上面的代码定义了Shape类和两个派生类Rectangle和Triangle。Shape类中定义了一个抽象方法Area(),并在Rectangle和Triangle中实现了这个抽象方法。在Main方法中,创建了一个Rectangle对象 r 和一个Triangle对象 t,并分别调用它们的Area()方法计算出它们的面积。
5. 接口示例

  C#接口是一种约定,是一个抽象的类型,它定义了一组公共的方法、属性、索引器和事件,这些成员没有实现细节和实现代码,只定义了接口的行为。
5.1 接口语法

定义接口的语法如下:
  1. interface 接口名称
  2. {
  3.   方法1
  4.   方法2
  5.   属性1
  6.   索引器1
  7.   事件1
  8. }
复制代码
其中,方法、属性、索引器和事件都是接口的成员,它们都没有实现,只是定义了行为的名称和参数。
方法定义的语法如下:
返回类型 方法名称(参数列表);
属性定义的语法如下:
属性类型 属性名称 { get; set; }
索引器定义的语法如下:
索引器类型 this[索引器参数] { get; set; }
事件定义的语法如下:
event 事件委托类型 事件名称;
其中,事件委托类型是一个Delegate类型。
5.2 接口使用示例

  定义一个接口之后,可以通过继承或实现来使用接口。接口的继承使用“:”符号,需要注意的是,如果一个类实现了一个接口,那么它必须实现接口中所有的方法和属性。下面是接口示例:
  1. interface IShape
  2. {
  3.   double Perimeter();
  4.   double Area();
  5. }
  6. interface ICircle : IShape
  7. {
  8.   double Radius { get; set; }
  9. }
  10. interface IRectangle : IShape
  11. {
  12.   double Width { get; set; }
  13.   double Height { get; set; }
  14. }
  15. class Circle : ICircle
  16. {
  17.   public double Radius { get; set; }
  18.   public double Perimeter()
  19.   {
  20.     return 2 * Math.PI * Radius;
  21.   }
  22.   public double Area()
  23.   {
  24.     return Math.PI * Radius * Radius;
  25.   }
  26. }
  27. class Rectangle : IRectangle
  28. {
  29.   public double Width { get; set; }
  30.   public double Height { get; set; }
  31.   public double Perimeter()
  32.   {
  33.     return 2 * (Width + Height);
  34.   }
  35.   public double Area()
  36.   {
  37.     return Width * Height;
  38.   }
  39. }
  40. class Program
  41. {
  42.   static void Main(string[] args)
  43.   {
  44.     Circle c = new Circle();
  45.     c.Radius = 1;
  46.     Console.WriteLine("Circle:  Perimeter = {0}, Area = {1}", c.Perimeter(), c.Area());
  47.     Rectangle r = new Rectangle();
  48.     r.Width = 2;
  49.     r.Height = 3;
  50.     Console.WriteLine("Rectangle:  Perimeter = {0}, Area = {1}", r.Perimeter(), r.Area());
  51.   }
  52. }
复制代码
  上面的代码定义了IShape、ICircle和IRectangle三个接口、以及Circle和Rectangle两个类。其中,Circle类实现了ICircle接口,Rectangle类实现了IRectangle接口。在Main方法中,创建了一个Circle对象和一个Rectangle对象,并给它们的属性赋值。然后分别调用了Circle和Rectangle对象的Perimeter()和Area()方法输出结果。
运行程序,输出以下结果:
  1. Circle:  Perimeter = 6.28318530717959, Area = 3.14159265358979
  2. Rectangle:  Perimeter = 10, Area = 6
复制代码
  可以看到,通过使用接口,我们可以很方便地定义出不同的形状,然后计算出它们的周长和面积。这就展示了接口在C#编程中的重要地位。
  想必大家看到这里对于多态性的实现方式已经有了一定的了解,不知大家是否发现,这些方式中,抽象方法和虚方法是如此的相似,那么我们就有了新的疑问:两者有何区别?使用场景是否有所不同?
在下面这篇随笔中,我针对这个问题进行了深入学习:C#中抽象方法与虚方法的区别

来源:https://www.cnblogs.com/letmebaby/archive/2023/03/27/17255211.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具