8. 多态

类的多态:

  (1)多态性就是指在程序运行时,不同对象对同一个方法调用的不同行为。即执行的虽然是一个调用方法的语句,却可以根据派生类对象的不同类型完成不同方法的具体实现;

  (2)实现多态性:方法重载、方法覆盖、方法重写、接口实现。

  (3)在面向对象编程中,多态往往表现为“一个接口,多个功能”。

  (4)多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。

静态多态性:

  在编译时,函数和对象的连接机制被称为早期绑定,也被称为静态绑定。C#提供了两种技术来实现静态多态性。分别为:函数重载、运算符重载。

动态多态性:

  动态多态性是通过抽象类和虚方法实现的。C#用关键字abstract创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象类时,实现即完成。虚方法使用关键字virtual实现。

多态的实现:

在C#中,动态多态性和静态多态性都是通过多态(Polymorphism)的概念来实现的,但它们在使用方式和实现方式上有所不同。

  1. 动态多态性:
    • 动态多态性是指在运行时根据对象的实际类型来确定调用哪个方法的能力。
    • C# 中的动态多态性通常通过虚方法(Virtual Methods)和重写(Override)来实现。子类可以重写父类的虚方法,而在运行时根据对象的实际类型来调用相应的重写方法。
    • 例如,在基类中声明一个虚方法,然后在子类中重写这个方法,当调用该方法时,实际执行的是子类中重写的方法。

示例代码如下:

class Shape
{
    public virtual void Draw()
    {
        Console.WriteLine("Drawing a shape");
    }
}

class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a circle");
    }
}

Shape shape = new Circle();
shape.Draw(); // 实际调用的是 Circle 类中的 Draw 方法
  1. 静态多态性:
    • 静态多态性是指在编译时根据变量的声明类型来确定调用哪个方法的能力。
    • C# 中的静态多态性通过方法重载(Method Overloading)和运算符重载(Operator Overloading)来实现。在编译时根据方法的参数类型和数量来确定调用哪个重载版本。
    • 例如,可以定义多个同名方法,它们具有不同的参数类型或数量,编译器会根据调用时传递的参数类型选择合适的方法。

示例代码如下:

class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }

    public double Add(double a, double b)
    {
        return a + b;
    }
}

Calculator calc = new Calculator();
int result1 = calc.Add(1, 2);         // 调用 int 版本的 Add 方法
double result2 = calc.Add(1.5, 2.5);  // 调用 double 版本的 Add 方法

总的来说,动态多态性是在运行时确定调用哪个方法,而静态多态性是在编译时确定调用哪个方法。

1、方法重载:同一类中,方法名相同,参数的列表与返回值不同。

2、方法覆盖:子类继承父类而且这是必须的,在子类中用 new 关键字修饰 定义的与父类中同名的方法,叫覆盖。

3、方法重写:重写方法即用相同的签名重写所继承的方法,即具有相同的方法名、返回类型和参数表。(使用关键字 override)

  虚方法

    若一个实例方法的声明中含有 virtual 修饰符,则称该方法为虚方法。此方法在子类中可以重写(使用关键字 override);

  抽象方法

    (1)抽象类不明确提供实现方法,必须由其子类实现它 的抽象方法;

    (2)定义基类中的抽象方法,则派生类必须重写该方法;

    (3)抽象方法一定属于抽象类,但抽象类不一定要包含抽象方法;

    (4)如果我们不需要使用父类创建对象,他的存在只是为供子类继承。可以将父类写成抽象(关键字 abstract)类,将父类写成抽象方法,子类中的方法仍用关键字 override 重写。

例1:虚方法的创建与调用:

 1     class class1 //新建一个类
 2     {
 3         //默认的方法是被指定为私有的,只能在当前类中进行访问。若需要在其他类中进行访问,
 4         //就需要将其指定为 public
 5         public virtual void virtualMethod()//新建一个虚方法
 6         {
 7             Console.WriteLine("这是一个虚方法");
 8         }
 9 
10         public void notVirtualMethod()//新建一个非虚方法
11         {
12             Console.WriteLine("这是一个非虚方法");
13         }
14     }
15     class Program
16     {             
17         static void Main(string[] args)
18         {
19             //调用虚方法和非虚方法
20             class1 c1 = new class1();
21             c1.virtualMethod();
22             c1.notVirtualMethod();
23             Console.ReadKey();            
24         }        
25     }

 

例2:重写虚方法:

 1     class class1 //新建一个类
 2     {
 3         //新建一个虚方法,
 4         //如果在方法中加入 sealed 关键字,
 5         //即 public virtual sealed void virtualMethod()则不允许class2重写方法
 6         public virtual void virtualMethod()                                                                  
 7         {
 8             Console.WriteLine("这是一个虚方法,可以被重写");
 9         }
10     }
11 
12     //再建一个继承类用于重写方法,class2继承与class1
13     class class2 : class1                                   
14     {
15         public override void virtualMethod()
16         {
17             Console.WriteLine("这是一个重写方法");
18         }
19     }

4、接口实现:(接口名称一般以 “I” 作为首字母)

  (1)接口是指定一组函数成员而不实现成员的引用类型,派生类可以实现接口;
  (2)接口声明不包括数据成员,只能包含方法、属性、事件、索引等成员;
  (3)可以利用接口实现多态,同时接口也弥补了C#单一继承的弱点;
  (4interface 关键字定义接口,接口成员的访问级别是默认的(public);
  (5)接口一旦被实现,实现类必须实现接口中的所有成员,除非实现类本身是抽象类。

5、sealed密封类:

  (1)密封类表示不能继承该类,密封方法表示不能重写该方法;
  (2)可以覆盖父类的密封方法,与父类中的方法是否为密封没有关系。

6、关键字的理解:

  (1)interface: 引入方法的名称,需要实现接口里面所有的方法;
  (2)virtual: 方法的第一个实现,以后还希望子类去不断完善重写他;
  (3)override: 方法的另一个实现;
  (4)sealed: 方法的最后一个实现。方法已经很完善了,我们不需要子类去重写他。

7、使用什么方法实现多态,取决于我们是否需要使用基类实例化的对象。需要时使用虚方法,不需要时使用抽象类。

 

posted @ 2017-10-04 22:22  LiuChangwei  阅读(253)  评论(0编辑  收藏  举报