zoukankan      html  css  js  c++  java
  • 多态的实现(重载,虚方法,抽象类,接口)

    1.前言

    多态是指,在同一个方法中,由于参数不同而导致执行效果各异。多态的实现方式主要是通过函数、运算符重载,虚成员,以及抽象类实现和接口。下面的内容就详细介绍一下前三种多态的实现形式。

    2.方法重载

     在同一作用域范围内,可以为同一个方法名声明多个定义,但是方法之间的定义必须不同,可以是参数列表的类型或个数的差异,但不可以重载只有返回类型不同的函数。下面的示例展示了如何实现方法的重载。

    class Person
    {
        public void Show()
        {
            Console.WriteLine($"name: kyle");
        }
        public void Show(int age)
        {
            Console.WriteLine($"name: kyle, age: {age}");
        }
    }
    class Program { static void Main(string[] args) { Person p = new Person(); p.Show(); p.Show(23); Console.ReadKey(); } }

    输出结果如下:

    name: kyle
    name: kyle, age: 23

    常见的函数重载是对 Object 类中的 ToString()方法进行重载:

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    
        public override string ToString()
        {
            return "Person: " + Name + " " + Age;
        }
    }

    其测试代码及结果如下:

    Person person = new Person { Name = "John", Age = 12 };
    Console.WriteLine(person);
    // Output:
    // Person: John 12

    3.运算符重载

    可以重定义或重载 C# 中内置的运算符,以此使用用户自定义类型的运算符。重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来定义的。与其他函数一样,重载运算符有返回类型和参数列表。

    下面的代码演示了运算符 + 的重载:

    class Box
    {
        double length;
        double width;
        public Box(double l, double w)
        {
            length = l;
            width = w;
        }
        public double Area()
        {
            return length * width;
        }
        public static double operator + (Box box1, Box box2)
        {
            return box1.Area() + box2.Area();
        }
    }
    class Program { static void Main(string[] args) { Box b1 = new Box(2.3, 1.2); Box b2 = new Box(4.4, 2.6); double total = b1 + b2; Console.WriteLine($"total area is {total}"); Console.ReadKey(); } }

    输出结果如下:

    total area is 14.2

    3.虚成员

    3.1 override重写

    当派生类从普通基类继承时,它会获得基类的所有公开方法、字段、属性和事件,当基类的成员声明为 virtual 时,派生类还可以对基类的成员(除字段)进行重写。在进行成员的重写时,派生类中需使用 override 关键字显示成员的重写。

    下面的代码展示了对基类中的虚成员的重写:

    public class BaseClass
    {
        public virtual void DoWork() { }
        public virtual int WorkProperty
        {
            get { return 0; }
        }
    }
    public class DerivedClass : BaseClass { public override void DoWork() { } public override int WorkProperty { get { return 0; } } }

    在使用 override 重写虚成员时,会对基类中的虚方法的覆盖,因此即便将派生类的示例转为基类的实例,仍会调用重写后的新成员,调用过程及结果如下:

    DerivedClass B = new DerivedClass();
    B.DoWork();  // Calls the new method.
    
    BaseClass A = (BaseClass)B;
    A.DoWork();  // Also calls the new method.

    3.2 使用新成员隐藏基类成员

    如果不希望覆盖掉基类中的既有虚成员,可以通过 new 关键字(默认),从而禁止派生类参与基类的虚成员调用。

    以下代码展示了如何使用新成员来隐藏基类成员,而不是重写覆盖:

    public class BaseClass
    {
        public void DoWork() { WorkField++; }
        public int WorkField;
        public int WorkProperty
        {
            get { return 0; }
        }
    }
    
    public class DerivedClass : BaseClass
    {
        public new void DoWork() { WorkField++; } // 不覆盖基类虚方法
        public new int WorkField;
        public new int WorkProperty
        {
            get { return 0; }
        }
    }

    在使用 new 关键字重写虚成员后,如果将派生类的实例转换为基类的实例,将会调用基类原有的虚成员,调用过程及结果如下:

    DerivedClass B = new DerivedClass();
    B.DoWork();  // Calls the new method.
    
    BaseClass A = (BaseClass)B;
    A.DoWork();  // Calls the old method.

    3.3 阻止派生类重写虚成员

    在类的继承过程中,虚成员默认始终保持其虚拟性(因此 override 关键字声明的重写成员也具有虚拟性),如果希望停止其虚拟继承,可以将虚成员声明为 sealed 来实现,其实现代码如下:

    public class A
    {
        public virtual void DoWork() { }
    }
    public class B : A
    {
        public override void DoWork() { }
    }
    
    public class C : B
    {
        public sealed override void DoWork() { }
    }

    在使用 sealed 声明虚成员之后,有 C 继承而来的类中的 Dowork() 不再保留虚拟性,但对于 C 的实例而言仍旧是虚拟的。C 的派生类可以通过 new 关键字最后重写 C 中的 Dowork() :

    public class D : C
    {
        public new void DoWork() { }
    }

    3.4 在派生类中访问基类虚成员

    如果要在派生类中直接访问基类的虚成员,可以使用 base 关键字进行访问,示例代码如下:

    public class Base
    {
        public virtual void DoWork() {/*...*/ }
    }
    public class Derived : Base
    {
        public override void DoWork()
        {
            //Perform Derived's work here
            //...
            // Call DoWork on base class
            base.DoWork();
        }
    }

    4.抽象类

    通过 abstract 关键字声明一个抽象类,例如:

    public abstract class A
    {
        // Class members here.
    }

    抽象类不可以进行实例化,其作用是作为一个可供多个派生类继承的通用基类。在抽象类中可以定义字段、属性、方法等,还可以通过关键字 abstract 添加到方法的返回类型前定义一个抽象方法,例如:

    public abstract class A
    {
        public int name;
        public string Show()
        {
            return "string";        
        }
        public abstract void DoWork(int i);
    } 

    抽象方法没有实现,抽象类的派生类必须实现所有的抽象方法。当抽象类从基类继承虚方法时,抽象类也可以使用抽象方法重写虚方法,例如:

    public class D
    {
        public virtual void DoWork(int i)
        {
            // Original implementation.
        }
    }
    
    public abstract class E : D
    {
        public abstract override void DoWork(int i);
    }
    
    public class F : E
    {
        public override void DoWork(int i)
        {
            // New implementation.
        }
    }

    继承抽象方法的类无法访问方法的原始实现,即类 F 上的实例无法调用 D 中的 DoWork() ,通过这种方式,抽象类可强制派生类向虚拟方法提供新的方法实现。

    由于抽象类需要作为基类由派生类继承,所以,抽象类无法使用 sealed 关键字和 static 关键字进行声明。

    把圈子变小,把语言变干净,把成绩往上提,把故事往心里收,现在想要的以后你都会有。
  • 相关阅读:
    ArcGIS超级工具SPTOOLS-制图篇
    ArcGIS超级工具SPTOOLS-MXD操作篇
    ArcGIS超级工具SPTOOLS-影像的批量裁剪和批量合并
    Get Raster Properties获得栅格的信息
    ArcGIS超级工具SPTOOLS-按属性裁剪,矢量数据批量裁剪,矢量数据批量合库
    ArcGIS超级工具SPTOOLS-SHP转数据库,批量数据库转数据库,栅格彩色转黑白
    ArcGIS超级工具SPTOOLS-锐角检查,获得内角并判断是否凸多边形,获得线(面)两个折点方向
    ArcGIS超级工具SPTOOLS-线封闭,点集转面
    ArcGIS超级工具-征地部标准坐标导出导入 SPTOOLS
    arcgis的arcpy写入几何怎么创建一个空心面要素并读取几何和属性信息,根本不够管
  • 原文地址:https://www.cnblogs.com/jizhiqiliao/p/9809480.html
Copyright © 2011-2022 走看看