zoukankan      html  css  js  c++  java
  • .NET面向对象特性之多态

                                                        前言                                      

             上一篇总结了面向对象三大特性之一的继承,再接再厉,这一章继续总结多态。同时把继承中涉及到多态的内容进一步补充扩展。可以说“继承”是多态的根基。但继承主要关注的是“共通性”,而多态主要关注的是“差异性”。

    一.多态介绍                                                          

    关于多态的定义:可以呈现不同形式的能力或状态。这一术语来源于生物系统,意指同族生物具有的相同特征。而在.NET 中,多态指同一操作作用于不同的实例,产生不同运行结果的机制。也就是不同对象接受到相同消息时会产生不同动作。

    eg:在现实生活中不同的环境下我们表现为不同的角色,遵循不同的规则。比如,在学校我们是我们是学生,在家我们是儿女,在饭店我们是客人,同一个不同环境下不同的角色,不同的规则。

    二.编译时多态

    编译时多态:是指参数列表的不同, 来区分不同的函数, 在编译后, 就自动变成两个不同的函数名.

    1.方法重载:方法名相同而方法参数列表不同。

      参数列表不同:(满足以下之一即可)

    (1)参数的个数不同

      eg: void function(int x,int y)  &&  void function(int x,int y,int z)

    (2)参数的个数相同但类型不同

      eg:void function (int x,int y)  &&  (void function(string a,string b)    ||  void function(int x,string a)  ……)

    (3)参数类型和个数相同,但顺序不同

      eg:void function(int x,string a) && void function(string a,intx )

      注意:方法的返回类型不是方法重载的判断条件。

      eg: string function();&&void function() 不构成重载。

       当方法重载的个数太多的时候,太多重载就麻烦了,这时可以用参数数组(params数组)。关于参数数组的介绍此处省略。

    2.继承中的方法重载

    当父类与子类重名时的方法重载:

    复制代码
    Class  Parent
    
    {
    
       public void function()
      {
          Console.WriteLine("parent");
       }
    
    }
    
    Class Child:Parent
    
    {
        public void function()
       {
          Console.WriteLine("Child");
        }
    }
    复制代码

    Parent p = new Parent();
    p.function();    //输出 parent

    Child c=new Child();

    c.function();    //输出Child

    当父类与子类方法相同时,调用哪个方法由对象变量的类型决定。

    Parent  p2 = new Child();

    p2.function();   //输出parent

    所以更准确的说法是:当分别位于父类和子类的方法相同时,调用哪个方法由对象变量的编译时类型决定。

    如果需要调用子类的怎么办,这时候就需要强制转换。

    ((Child)p2).function(); (其实干嘛p2不直接定义为Child类型呢?不是更简单)

    好了,运行吧,但是出现了一条警告:隐藏了继承的成员。这时候就需要用到new关键字来消除隐藏。

        方法重载是在编译的时候根据参数列表的不同,从而调动了方法名相同的不同函数。这就体现了多态的特点,对同一消息产生不同动作。它是在编译时确定的,所以是编译时多态。

    ……先讲到这里,请对比下面运行时多态中的虚函数的多态……

    2.运算符重载

    为了解决同一操作符施加于不同类型的对象时拥有不同的含义的问题,提供了运算符重载。

    eg:我们可以对数字进行相加,但是有时候我们需要对不同对象里的数字进行相加,比如,我们数学上的两个复数相x1=a+bi,x2=c+di,对x1和x2相加。

    格式为:

    public static 返回值类型 operator unary-operator ( 参数列表 )
    
    {
         方法体
     }

    这里给出一个一元运算符重载的例子:

     运算符重载例子

    class Point
    {
    private int x,y;
    public Point(int a, int b)
    {
    x = a;
    y = b;
    }
    public static Point operator ++(Point p)
    {
    p.x ++;
    p.y ++;
    return p;
    }
    public void Display()
    {
    Console.WriteLine("Point.x = {0}, Point.y = {1}",x,y);
    }
    public static Point operator +(Point p1,Point p2)
    {
    Point p = new Point(0,0);
    p.x = p1.x + p2.x;
    p.y = p1.y + p2.y;
    return p;
    }
    static void Main(string[] args)
    {
    Point a = new Point(10,20);
    Point b = new Point(30,40);
    a = a + b;
    a.Display();
    a ++;
    a.Display();
    }
    }

    运算符重载例子

    注意:是几元运算符,参数就有几个。

    总结:编译时的多态,一般包括方法重载和运算符重载,在编译时通过方法的参数列表和返回值决定不同操作。(这里指的是非虚函数的情况下)

    三.运行时多态

    运行时多态:也就是动态绑定,是指在执行期间(而非编译期间)判断所引用对象的实际类型,根据实际类型判断并调用相应的属性和方法。(在程序运行前不知道,会调用那个方法, 而到运行时, 通过运算程序,动态的算出被调用的地址. 动态调用在继承的时候,方法名 参数列表完全相同时才出现运行时多态!)

    1.虚函数

    先看代码

     虚函数

    public abstract class Animal
    {
    public abstract void ShowType();
    public void Eat()
    {
    Console.WriteLine("Animal always eat.");
    }
    }
    public class Bird: Animal
    {
    private string type = "Bird";
    public override void ShowType()
    {
    Console.WriteLine("Type is {0}", type);
    }
    private string color;
    public string Color
    {
    get { return color; }
    set { color = value; }
    }
    }
    public class Chicken : Bird
    {
    private string type = "Chicken";
    public override void ShowType()
    {
    Console.WriteLine("Type is {0}", type);
    }
    public void ShowColor()
    {
    Console.WriteLine("Color is {0}", Color);
    }
    //测试
    public class Test
    {
    public static void Main()
    {
    Bird bird = new Bird();
    Chicken chicken = new Chicken();
    }
    }

    虚函数

    由于 Animal 为抽象类,我们只创建 Bird 对象和 Chicken对象。

      很容易看就知道bird的引用类型是Bird,而创建的对象也是Bird。Chicken的引用类型是Chicken,创建的对象是Chicken。

      再看这行代码:Bird bird2 = new Chicken();

      bird2是什么类型呢?bird2对象调用子类还是父类的方法?

      在这种情况下(虚方法)bird2的调用方法,取决于其创建的对象类型,而不是它的引用类型。如上 Bird bird2 = new Chicken()时,bird2创建对象为 Chicken 类型,而不用关注 bird2 的引用类型是否为 Bird。引用类型只是决定了方法的访问权限。

       也可以这样理解:

       Bird bird2=new Chicken();可以看做

       Bird bird2=new Bird();

       Chiken chiken=new Chiken();

       bird2=chiken;

       所以,bird2还是chiken对象。那么这个引用类型Bird有什么用?被子类隐藏掉的方法,必须通过转化为父类才能调用其方法。否则只能访问子类的方法。通过这种转换就可以调用父类中被隐藏的方法。

    调用虚函数时,具体调用哪个函数不是在编译时候确定的,而是在运行时根据对象的真实类型而定的。

    2.抽象类

    3.接口多态

    暂时还来不及总结,不过看到一篇不错的博文:http://www.cnblogs.com/if404/archive/2011/10/28/2227197.html

    待续……

    目前水平有限,随着学习的深入会不断更新,精益求精。欢迎补充。

    说明:我是IT边上的一只蜗牛,尽管前面道路漫漫,但我始终渴望前行。

     
     
    分类: .NET
    标签: C#.NET
  • 相关阅读:
    近期简单题炸分总结
    传输层中的端口号
    TCP的三次握手与四次挥手
    ppq的面试题总结
    一个C++源文件从文本到可执行文件经历的过程
    C++中的&符号的运用:引用、取地址和右值引用
    C++中的拷贝构造、赋值构造函数
    C++中的虚函数
    函数指针与回调函数
    C++中的智能指针
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3364216.html
Copyright © 2011-2022 走看看