C#多态性的理解与梳理

C#静态多态性与动态多态性

  • C#的多态性
    • 含义
    • 静态多态性
      • 函数重载
      • 运算符重载
    • 动态多态性
      • 抽象类
      • 虚方法
    • abstract方法和virtual方法的区别

这篇文章出发点是对我认为对在C#多态性方面的理解过程中易出现差错的地方做一个详细记录与梳理。

C#的多态性

含义

多态是同一个行为具有多个不同表现形式或形态的能力。多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。在 C# 中,每个类型都是多态的,因为包括用户定义类型在内的所有类型都继承自 Object。概要理解来说,多态就是同一个接口,使用不同的实例而执行不同操作。

静态多态性

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

函数重载

您可以在同一个范围内对相同的函数名有多个定义。函数的定义必须彼此不同,可以是参数列表中的参数类型不同,也可以是参数个数不同。不能重载只有返回类型不同的函数声明!举例如下图所示:

using System;

namespace _08___多态性
{
    public class Test
    {
        public int sum(int a, int b)
        {
            return a + b;
        }
        public int sum(int a, int b,int c)
        {
            return a + b + c;
        }
    }
        

    class Program
    {
        static void Main(string[] args)
        {
            Test t1 = new Test();
            int result1 = t1.sum(1, 2);
            int result2 = t1.sum(1, 2, 3);
            Console.WriteLine("result1:{0}", result1);
            Console.WriteLine("result2:{0}", result2);
        }
    }
}

运算符重载

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

class Person
    {
        private int age = 1;
        private float height = 1.1f;
        public static Person operator+ (Person a, Person b)
        {
            Person p1 = new Person();
            p1.age = a.age + b.age;
            p1.height = a.height + b.height;
            return p1;
        }
        public void getmsg()
        {
            Console.WriteLine("age:{0}", age);
            Console.WriteLine("height:{0}", height);
        }
    }
    class Program
    {

        static void Main(string[] args)
        {
            Person p1 = new Person();
            Person p2 = new Person();
            Person p3 = new Person();
            p3 = p1 + p2;
            p3.getmsg();
            Console.WriteLine("end!");
        }
    }

动态多态性

动态多态性是通过 抽象类 和 虚方法 实现的。

抽象类

C# 允许使用关键字 abstract 创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象类时,实现即完成。抽象类包含抽象方法,抽象方法可被派生类实现。派生类具有更专业的功能。
抽象类是基于严格面向对象编程思想,用关键词abstract创建抽象类,用于提供接口的部分类的实现(这句话有点绕,个人理解为实现以类的形式提供接口的部分),接口不能提供实现,抽象类中可以有实现。接口与抽象类一起使用,可以达到父类中不能实现的子类必须实现,父类中有实现子类中就不需要实现的目的。举例如下图所示:

    abstract class A
    {
        abstract public void method_a();
    }
    class B:A
    {
        public override void method_a()
        {
            Console.WriteLine("重写继承于抽象类A中的抽象方法method_a的实现");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            B b1 = new B();
            b1.method_a();
        }
    }

虚方法

当有一个定义在类中的函数需要在继承类中实现时,可以使用虚方法。虚方法是使用关键字 virtual 声明的。虚方法可以在不同的继承类中有不同的实现。对虚方法的调用是在运行时发生的。动态多态性是通过 抽象类 和 虚方法 实现的。(根据IDE10086命名规范,虚方法方法名首字母需为大写),举例说明如下:

//动态多态性,虚方法
    class A
    {
        public int num1 = 1;
        
        //声明虚方法
        public virtual void Method_a()
        {
            num1 = 10;
            Console.WriteLine("num:{0}", num1);
        }
    }
    class B:A
    {
        public override void Method_a()
        {
            num1 = 2;
            Console.WriteLine("num:{0}", num1);
            //调用原虚函数,做对比
            base.Method_a();
        }
    }
    class C:A
    {
        public override void Method_a()
        {
            num1 = 3;
            Console.WriteLine("num:{0}", num1);
            base.Method_a();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var objs = new List<A>
            {
                new B(),
                new C()
            };

            foreach (var obj in objs)
            {
                obj.Method_a();
            }
        }
    }

abstract方法和virtual方法的区别

1.virtual修饰的方法必须有实现(哪怕是仅仅添加一对大括号),abstract修饰的方法一定不能实现。
2.virtual可以被子类重写,而abstract必须被子类重写。
3.如果类成员被abstract修饰,则该类前必须添加abstract,因为只有抽象类才可以有抽象方法。
4.无法创建abstract类的实例,只能被子类继承,子类若不实现abstract类中的抽象方法,依然是个抽象类,不能被实例化;相反,若子类实现abstract类的抽象方法,则子类可以被实例化。

你可能感兴趣的:(C#)