• C# 笔记C# 多态性3


    C# 笔记--C# 多态性 分类:C# 笔记2008.1.13 18:08 作者:jun | 评论:0 | 阅读:2311
    C# 入门经典
    ---C# 多态性

    刚刚入手,感觉书中对于这一块讲的很模糊,四处搜索,请教了一下,感觉小有收获, 谨小记于下:



    多态性(Polymorphism)一词最早用于生物学,指同一种族的生物体具有相同的特性。
    在C#中多态性的定义是:同一操作作用于不同的类的实例、不同的类将进行不同的解释、最后产生不同的执行结果。

    C#支持两种类型的多态性:
    编译时的多态性(静态联编)
    编译时的多态性是通过重载来实现的。方法重载和操作符重载、它们都实现了编译时的多态性。
    对于非虚的成员来说系统在编译时根据传递的参数、返回的类型等信息决定实现何种操作。
    运行时的多态性(动态联编)
    运行时的多态性就是指直到系统运行时才根据实际情况决定实现何种操作C#中运行时的多态性。
    通过虚成员实现。
    编译时的多态性为我们提供了运行速度快的特点而运行时的多态性则带来了高度灵活和抽象的特点。

    虚方法
    当类中的方法声明前加上了virtual 修饰符,我们称之为虚方法,反之为非虚。
    使用了virtual 修饰符后不允许再有static,
    abstract, 或 override 修饰符。
    对于非虚的方法,无论被其所在类的实例调用还是被这个类的派生类的实例调
    用,方法的执行方式不变。而对于虚方法它的执行方式可以被派生类改变,这种改
    变是通过方法的重载来实现的。
    下面的例子说明了虚方法与非虚方法的区别:

    注意 : 

    .派生类变量可以直接赋值给基类变量(装箱)。若要将一基类变量赋值给其派生类变量,则该基类变量的原始类型必须为该派生类变量或者为派生为该派生类的变量(拆箱)

    2. 将基类变量的值赋为派生类变量时, 若基类的方法被派生类隐藏(New), 则基类变量调用该方法时,仍将调用基类的方法. 若基类的方法被派生类重写时(Override), 则将调用派生重写的方法.

    3.除第2 条的情况外,基类变量调用其基类方法.


    程序清单
    using System;
    class A
    {
    public void F() { Console.WriteLine("A.F"); }
    public virtual void G() { Console.WriteLine("A.G"); }
    }
    class B: A
    {
    new public void F() { Console.WriteLine("B.F"); }
    public override void G() { Console.WriteLine("B.G"); }
    }
    class Test
    {
    static void Main() {
    B b
    = new B();

    A a
    =new A();

    a.F();

    b.F();

    a.G();

    b.G();
    a
    = b; // 将派生类转为基类
    a.F();
    b.F();
    a.G();
    b.G();


    }
    }
    例子中A 类提供了两个方法,非虚的F 和虚方法G 。类B 则提供了一个新的非虚的方法F,
    从而隐藏了继承的F 。类B 同时还重写了继承的方法G。 那么输出应该是

    A.F

    B.F

    A.G

    B.G


    A.F
    B.F
    B.G
    B.G




    注意到本例中方法a.G() 实际调用了B.G 而不是A.G ,这是因为编译时值为A,但运行时值为B。
    所以B 完成了对方法的实际调用。

    在派生类中对虚方法进行重载
    先让我们回顾一下普通的方法重载。
    普通的方法重载指的是类中两个以上的方法,包括隐藏的继承而来的方法,取的名字相同,
    只要使用的参数类型或者参数个数不同,编译器便知道在何种情况下应该调用哪个方法。
    而对基类虚方法的重载是函数重载的另一种特殊形式。
    在派生类中重新定义此虚函数时要求的是方法名称,返回值类型,参数表中的参数个数,类型,顺序都必须
    与基类中的虚函数完全一致。在派生类中声明对虚方法的重载要求在声明中加上override 关键字,
    而且不能有new,
    static 或virtual 修饰符。
    我们用汽车类的例子来说明多态性的实现
    程序清单:
    using System;
    class Vehicle//定义汽车类
    {
    public int wheels; //公有成员轮子个数
    protected float weight; //保护成员重量
    public Vehicle(int w,float g){
    wheels
    = w;
    weight
    = g;
    }
    public virtual void Speak(){
    Console.WriteLine(
    "the w vehicle is speaking!");
    }
    };
    class Car:Vehicle //定义轿车类
    {
    int passengers; //私有成员乘客数
    public Car(int w,float g,int p) : base(w,g)
    {
    passengers
    = p;
    }
    public override void Speak(){
    Console.WriteLine(
    "The car is speaking:Di-di!");
    }
    }
    class Truck:Vehicle //定义卡车类
    {
    int passengers; //私有成员乘客数
    float load; //私有成员载重量
    public Truck (int w,float g,int p ,float l) : base(w,g)
    {
    passengers
    = p;
    load
    = l;
    }
    public override void Speak(){
    Console.WriteLine(
    "The truck is speaking:Ba-ba!");
    }
    }
    class Test
    {
    public static void Main(){
    Vehicle v1
    = new Vehicle(2,3);
    Car c1
    = new Car(4,2,5);
    Truck t1
    = new Truck(6,5,3,10);

    v1.Speak();
    v1
    = c1;
    v1.Speak();
    c1.Speak();
    v1
    = t1;
    v1.Speak();
    t1.Speak();
    Console.ReadKey();
    }
    }

    分析上面的例子我们看到
    ? Vehicle 类中的Speak 方法被声明为虚方法,那么在派生类中就可以重新定义
    此方法;
    ? 在派生类Car 和Truck 中分别重载了Speak 方法。派生类中的方法原型和基类
    中的方法原型必须完全一致;
    ? 在Test 类中创建了Vehicle 类的实例v1 ,并且先后指向Car 类的实例c1 和
    Truck 类的实例t1。

    运行该程序结果应该是
    The Vehicle
    is speaking!
    The car
    is speaking:Di-di!
    The car
    is speaking:Di-di!
    The truck
    is speaking:Ba-ba!
    The truck
    is speaking:Ba-ba!

    这里Vehicle 类的实例v1 先后被赋予Car 类的实例c1 以及Truck 类的实例t1的值。
    在执行过程中,v1 先后指代不同的类的实例从而调用不同的版本。
    这里v1 的Speak 方法实现了多态性,并且v1.Speak 究竟执行哪个版本不是在程序编译时确定的
    而是在程序的动态运行时根据v1 某一时刻的指代类型来确定的,所以还体现了动态的多态性。

    exercise:求输入结果。
    public class A
    {
    public virtual void Fun1(int i)
    {
    Console.WriteLine(i);
    }

    public void Fun2(A a)
    {
    a.Fun1(
    1);
    Fun1(
    5);
    }
    }


    public class B : A
    {
    public override void Fun1(int i)
    {
    base.Fun1 (i 1);
    }

    public static void Main()
    {
    B b
    = new B();
    A a
    = new A();
    a.Fun2(b);
    b.Fun2(a);
    }
    }

    Answer:
    /*
    2
    5
    1
    6
    */
  • 相关阅读:
    CentOS 6.7 如何启用中文输入法
    10w数组去重,排序,找最多出现次数(精华)
    win10虚拟机搭建Hadoop集群(已完结)
    Linux常用命令
    调用接口显示Required request body is missing
    Git 的使用
    Navicat创建事件,定时更新数据库
    mysql生成UUID
    时间戳与字符串相互转换
    牛客中的错题
  • 原文地址:https://www.cnblogs.com/beeone/p/1998303.html
Copyright © 2020-2023  润新知