c# 面相对象4-多态性

一、定义:

多态是面向对象程序设计的又一个特性。在面向过程的程序设计中,主要工作是编写一个个的过程或函数,这些过程和函数不能重名。例如在一个应用中,需要对数值型数据进行排序,还需要对字符型数据进行排序,虽然使用的排序方法相同,但要定义两个不同的过程(过程的名称也不同)来实现。

  在面向对象程序设计中,可以利用“重名”来提高程序的抽象度和简洁性。首先我们来理解实际的现象,例如,“启动”是所有交通工具都具有的操作,但是不同的具体交通工具,其“启动”操作的具体实现是不同的,如汽车的启动是“发动机点火——启动引擎”、“启动”轮船时要“起锚”、气球飞艇的“启动”是“充气——解缆”。如果不允许这些功能使用相同的名字,就必须分别定义“汽车启动”、“轮船启动”、“气球飞艇启动”多个方法。这样一来,用户在使用时需要记忆很多名字,继承的优势就荡然无存了。为了解决这个问题,在面向对象的程序设计中引入了多态的机制。

  多态是指一个程序中同名的不同方法共存的情况。主要通过子类对父类方法的覆盖来实现多态。这样一来,不同类的对象可以响应同名的方法来完成特定的功能,但其具体的实现方法却可以不同。例如同样的加法,把两个时间加在一起和把两个整数加在一起肯定完全不同。

  通过方法覆盖,子类可以重新实现父类的某些方法,使其具有自己的特征。例如对于车类的加速方法,其子类(如赛车)中可能增加了一些新的部件来改善提高加速性能,这时可以在赛车类中覆盖父类的加速方法。覆盖隐藏了父类的方法,使子类拥有自己的具体实现,更进一步表明了与父类相比,子类所具有的特殊性。

  多态性使语言具有灵活、抽象、行为共享的优势,很好地解决了应用程序函数同名问题。

二、实现的方法

      多态需要通过继承来实现。

三、分类

1、编译多态(重载overload)
 eg、 函数重载

重载(overload):在同一个作用域(一般指一个类)的两个或多个方法函数名相同,参数列表不同的方法叫做重载,它们有三个特点(俗称两必须一可以):

  • 方法名必须相同
  • 参数列表必须不相同
  • 返回值类型可以不相同

如:

1 public void Sleep()
2         {
3             Console.WriteLine("Animal睡觉");
4         }
5         public int Sleep(int time)
6         {
7             Console.WriteLine("Animal{0}点睡觉", time);
8             return time;
9         }

2、运行多态(重写override)

子类中为满足自己的需要来重复定义某个方法的不同实现,需要用override关键字,被重写的方法必须是虚方法,用的是virtual关键字。它的特点是(三个相同):

  • 相同的方法名
  • 相同的参数列表
  • 相同的返回值。
 1 如:父类中的定义:
 2         public virtual void EatFood()
 3         {
 4             Console.WriteLine("Animal吃东西");
 5         }
 6
 7        子类中的定义:
 8
 9         public override void EatFood()
10         {
11             Console.WriteLine("Cat吃东西");
12             //base.EatFood();
13         }

实现方式:

父类引用指向子类
例子:

 1 namespace mydemo1
 2 {
 3     class Ren
 4     {
 5         public virtual void Speak()//
 6         {
 7         }
 8     }
 9
10     class Ghost
11     {
12         public void Eat(Ren e)
13         {
14             e.Speak();
15             Console.WriteLine("人类真好吃!");
16         }
17     }
18
19     class China : Ren
20     {
21         public override void Speak()
22         {
23             Console.WriteLine("汉语");
24         }
25     }
26
27     class Usa : Ren
28     {
29         public override void Speak()
30         {
31             Console.WriteLine("English");
32         }
33     }
34
35     class Program
36     {
37         public static void Main(string[] args)
38         {
39             Ren a = new China();//父类的引用指向子类的实例
40             Ren b = new Usa();
41
42             //a.Speak();
43             //b.Speak();
44
45             Ghost g = new Ghost();
46             China c = new China();
47             Usa u = new Usa();
48
49             Random r = new Random();
50             int a = r.Next(0, 3);
51
52             if (a == 1)
53             {
54                 g.Eat(c);//改eat()方法传入的参数要求是Ren类的引用,可以向里面传其子类及父类的元素,子类对象代替父类对象
55             }
56             else
57             {
58                 g.Eat(u);
59             }
60
61
62         }
63     }
64 }

3、虚方法

:即为基类中定义的允许在派生类中重写的方法,使用virtual关键字定义。

如:

1  public virtual void EatFood()
2         {
3             Console.WriteLine("Animal吃东西");
4         }

注意虚方法也可以直接调用

   Animal a = new Animal();
            a.EatFood();

运行结果:

 4、抽象方法:在基类中定义的并且必须在派生类中重写的方法,使用abstract关键字定义。如:

public abstract class Biology
    {
        public abstract void Live();
    }
    public class Animal : Biology
    {
        public override void Live()
        {
            Console.WriteLine("Animal重写的抽象方法");
            //throw new NotImplementedException();
        }
    }

注意:抽象方法只能在抽象类中定义,如果不在抽象类中定义,则会报出如下错误:


5、
里氏代换原则和抽象依赖原则

里氏代换原则
如果某个方法接收的是父类引用,可以向里面传父类或其子类的元素,子类对象替代父类对象
例子:怪兽吃人

 1  class Guaishou
 2     {
 3         public void Eat(Ren r)
 4         {
 5             r.Jiao();
 6             Console.WriteLine("人类真好吃");
 7         }
 8     }
 9
10     class Ren
11     {
12         public virtual void Speak()
13         {
14             Console.WriteLine("说话");
15         }
16
17         public virtual void Jiao()
18         {
19             Console.WriteLine("55555555555555555");
20         }
21
22     }
23
24     class American:Ren
25     {
26         public override void Speak()
27         {
28             Console.WriteLine("Hello");
29         }
30
31         public override void Jiao()
32         {
33             Console.WriteLine("SOS");
34         }
35     }
36
37     class Chinese:Ren
38     {
39         public override void Speak()
40         {
41             Console.WriteLine("你好");
42         }
43         public override void Jiao()
44         {
45             Console.WriteLine("救命");
46         }
47
48     }
49
50     class Program
51     {
52         static void Main(string[] args)
53         {
54             //Ren a = new Chinese();
55             //a.Speak();
56             //a = new American();
57             //a.Speak();
58
59             Guaishou g = new Guaishou();
60
61             //Ren ren;
62
63             Random r = new Random();
64             int a = r.Next(0,3);
65
66             if(a==1)
67             {
68                 American ren= new American();
69                 g.Eat(ren);
70             }
71             else
72             {
73                Chinese  ren = new Chinese();
74                 g.Eat(ren);
75             }
76
77
78         }
79     }
80 }

抽象依赖原则

用父类的引用来指向子类的实例
例子:运行多态的例子

6、隐藏方法在派生类中定义的和基类中的某个方法同名的方法,使用new关键字定义。

如在基类Animal中有一方法Sleep():

        public void Sleep()
        {
            Console.WriteLine("Animal Sleep");
        }

则在派生类Cat中定义隐藏方法的代码为:

        new public void Sleep()
        {
            Console.WriteLine("Cat Sleep");
        }

            或者为:

        public new void Sleep()
        {
            Console.WriteLine("Cat Sleep");
        }    

注意:(1)隐藏方法不但可以隐藏基类中的虚方法,而且也可以隐藏基类中的非虚方法。

(2)隐藏方法中父类的实例调用父类的方法,子类的实例调用子类的方法。

(3)和上一条对比:重写方法中子类的变量调用子类重写的方法,父类的变量要看这个父类引用的是子类的实例还是本身的实例,如果引用的是父类的实例那么调用基类的方法,如果引用的是派生类的实例则调用派生类的方法。

7、例题

 1 public abstract class Biology
 2     {
 3         public abstract void Live();
 4     }
 5     public class Animal : Biology
 6     {
 7         public override void Live()
 8         {
 9             Console.WriteLine("Animal重写的Live");
10             //throw new NotImplementedException();
11         }
12         public void Sleep()
13         {
14             Console.WriteLine("Animal Sleep");
15         }
16         public int Sleep(int time)
17         {
18             Console.WriteLine("Animal在{0}点Sleep", time);
19             return time;
20         }
21         public virtual void EatFood()
22         {
23             Console.WriteLine("Animal EatFood");
24         }
25     }
26     public class Cat : Animal
27     {
28         public override void EatFood()
29         {
30             Console.WriteLine("Cat EatFood");
31             //base.EatFood();
32         }
33         new public void Sleep()
34         {
35             Console.WriteLine("Cat Sleep");
36         }
37         //public new void Sleep()
38         //{
39         //    Console.WriteLine("Cat Sleep");
40         //}
41     }
42     public class Dog : Animal
43     {
44         public override void EatFood()
45         {
46             Console.WriteLine("Dog EatFood");
47             //base.EatFood();
48         }
49     }

需要执行的代码:

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //Animal的实例
 6             Animal a = new Animal();
 7             //Animal的实例,引用派生类Cat对象
 8             Animal ac = new Cat();
 9             //Animal的实例,引用派生类Dog对象
10             Animal ad = new Dog();
11             //Cat的实例
12             Cat c = new Cat();
13             //Dog的实例
14             Dog d = new Dog();
15             //重载
16             a.Sleep();
17             a.Sleep(23);
18             //重写和虚方法
19             a.EatFood();
20             ac.EatFood();
21             ad.EatFood();
22             //抽象方法
23             a.Live();
24             //隐藏方法
25             a.Sleep();
26             ac.Sleep();
27             c.Sleep();
28             Console.ReadKey();
29         }
30     }
时间: 2024-10-13 11:26:07

c# 面相对象4-多态性的相关文章

Java对象的多态性

多态性在面向对象中主要有两种体现: <1>方法的重载与覆写 <2>对象的多态性 对象的多态性:向上转型:子类对象-->父类对象,向上转型会自动完成 向下转型:父类对象-->子类对象,向下转型时,必须明确地指明转型的子类类型 对象的向上转型 虽然使用的父类对象调用fun1方法,但是实际上调用的方法是被子类覆写过的方法,也就是说,如果对象发生了向上转型关系后,所调用的方法一定是被子类覆写过的方法. 但是父类的a无法调用b类中的fun3方法,因为这个方法只在子类中定义,而没有

js编程-面相对象

//js面相对象编程 //定义constructor构造方法 function myFn(name,sex){ this.name = name; this.sex = sex; } //用prototype追加属性方法 myFn.prototype.getName = function(inter){ console.log(this.name); console.log("兴趣:" + inter); return this.name; } //实例化myFn var newMy

Java面向对象-对象的多态性

Java面向对象-对象的多态性 Java中的多态性表现: 1,方法的重载和重写(覆盖): 2,可以用父类的引用指向子类的具体实现,而且可以随时更换为其他子类的具体实现: 我们先搞个父类Animal: 1 package com.java1234.chap03.sec13; 2 3 public class Animal { 4 5 public void say(){ 6 System.out.println("我是一个动物"); 7 } 8 } 再搞两个子类,分别是Dog和Cat类,

面向对象高级——接口的基本概念和对象的多态性

接口 需要掌握接口的定义格式及使用 掌握接口与抽象类的关系 具体内容: 接口是Java中最重要的概念,接口可以理解为一种特殊的类,里面全部是由全局常量和公共的抽象方法所组成. 如果一个类中完全是由全局常量(static final声明)和抽象方法组成,就可以将其定义成一个接口. 接口的定义格式: interface 接口名称{    全局常量:    抽象方法: }   interface A{ // 定义接口A public static final String AUTHOR = "刘勋&q

8.python之面相对象part.6(反射&__call__,__setattr__,__delattr__,__getattr__)

一.什么是反射? 反射,又被称为自省,主要是指程序本身可以访问,检测,和修改"自己",状态或行为的一种能力. 二.python是如何体现这种反射机制的? 通过字符串去操作对象相关的属性,python中,一切皆对象,所有的地方都可以用到反射. python内部提供了四个实现反射(自省)的函数,这四个函数可以适用于任何的类和对象(这是因为类本身也是一个对象!) 1.hasattr(object,str) 用来检测一个对象中是否有某个字符串对应的方法或者属性. 例如: l1 = [] pri

文成小盆友python-num7 -常用模块补充 ,python 牛逼的面相对象

本篇内容: 常用模块的补充 python面相对象 一.常用模块补充 1.configparser模块 configparser 用于处理特定格式的文件,起内部是调用open()来实现的,他的使用场景是操作特定格式的文件. 特定的格式如下: # [section1] #节点名称 k1 = v1 #值1 k2 = v2 #值2 [section2] #节点名称 k1 = v1 #值 获取文件中的所有节点 ##configparser 模块使用 #1.获取所有的节点 import configpars

c# 面相对象2-之封装性

c# 面相对象2-之封装性 一.封装特性: 这是一种隐藏的特性.可以用一个公式来展示类的封装特性: 封装的类=数据  +  对此数据进行的操作(即算法) 通俗的说,封装就是:包起外界不必要知道的东西,只向外界展露可供展示的东西. 在面向对象理论中,封装这个概念拥有更为宽广的含义.小到一个简单的数据结构,大到一个完成的软件子系统,静态的如某个软件系统要收集数据信息项,动态的如某个工作处理的流程,都可以封装到一个类中. 具备这种封装的意识,是掌握面向对象分析与设计技巧的关键 二.类的成员: 成员变量

java上转型和下转型(对象的多态性)

/*上转型和下转型(对象的多态性) *上转型:是子类对象由父类引用,格式:parent p=new son *也就是说,想要上转型的前提必须是有继承关系的两个类. *在调用方法的时候,上转型对象只能调用父类中有的方法,如果调用子类的方法则会报错 *下转型:是父类向下强制转换到子类对象 *前提是该父类对象必须是经过上转型的对象. * *代码示例:*/ 1 abstract class Parent{ 2 abstract void grow(); 3 } 4 class Son extends P

java 第十一天 面向对象(高级篇之接口、对象的多态性,instanceof)

接口的基本概念:接口的访问权限是public,关键字interface,子类通过implements关键字实现接口.一个子类可以同时实现多个接口. 对象的多态性: 两种体现形式:(1)方法的重载与覆写.(2)对象的多态性. 对象的多态性分两种: (1)向上转型:子类对象--→父类对象 (2)向下转型:父类对象--→子类对象 java中可以使用instanceof关键字判断对象到底是哪个类的实例 java 第十一天 面向对象(高级篇之接口.对象的多态性,instanceof),码迷,mamicod

递归函数、二分查找、面相对象初识、类空间,对象空间、组合、继承

一.递归函数 一般递归100多次,都没有解决的问题,放弃递归. 默认递归深度:998 修改默认递归次数 import sys sys.setrecursionlimit(100000) #设置十万次 count = 0 def func1(): global count count += 1 print(count) func1() func1() 用递归 解决一个年龄问题. alex 他比佩奇 大两岁.  4   age(3) + 2 佩奇 他比日天 大两岁.  3   age(2) + 2