• 深入浅出OOP(一): 多态和继承(早期绑定/编译时多态)


    

    在本系列中,我们以CodeProject上比較火的OOP系列博客为主。进行OOP深入浅出展现。

    不管作为软件设计的高手、或者菜鸟,对于架构设计而言。均须要多次重构、取舍。以有利于整个软件项目的健康构建,有些经验是前辈总结的,我们拿来使用就可以,有些是团队知识沉淀的,总之复用前人好的思想有利于降低返工。当然,在面试的时候,假设能环绕OOP大谈特谈,自然会加分多多的。

    開始阅读本系列博客的预备知识,多态、封装、面向对象编程等。请通过MSDN学习。

    例如以下图的术语,您应该耳熟能详的。本系列文章使用C#作为唯一脚本语言。

    image

    OOP

    1 是什么OOP。以及OOP的优势是什么?

    OOP代表的是面向对象编程(Object-Oriented Programming),它基于对象的总体进行编程,代替了基于过程函数的编程思想。

    详细实现是环绕对象进行数据、函数封装。而不是基于逻辑关系。

    OOP中的对象直达的是一个特定的类型、或者某类型的实例对象、很多其它时候是一个class。每一个class对象的结构基本类似,可是有各自特有的属性和数据值。对象之间可通过对外的接口进行訪问:方法、属性等。

    基于OOP的这些优势。独立的对象能够改动而不会影响到其它对象,这样会比較方便的升级软件降低潜在的bug。软件系统随着时间的推移,会变得越来越大。OOP编程思想有效的提高了系统代码的可读性和管理性。

    image

    2 OOP的概念是什么?

    以下用5个术语来说明OOP的详细概念是什么:

    • 数据抽象(Data Abstraction):数据抽象是对须要操作的物体进行建模的出发点,既对使用对象进行了抽象。隐藏了内部的细节(对使用的终于用户而言)。

      用户能够很方便的使用class的方法、数据。而不用关心数据创建、执行逻辑的背后复杂的过程。

      我们以真实世界为例,当你骑一辆自行车的时候,不用考虑变速齿轮的原理怎样驱动链条、车轮吧。

    • 继承(Inheritance):继承是OOP概念中最流行的一个概念。继承给程序猿提供了可复用代码的优势。

      基类定义好函数逻辑,子类通过继承,可实现直接訪问--就想子类自身的方法一样方便。

    • 数据封装(Data Encapsulation):对class的成员变量、成员函数通过訪问控制符进行包装。则称为数据封装。訪问控制符有public、Protected、Private、Internal 4种类型。

    • 多态(Polymorphism):对象可通过传递不同參数实现同样的动作,这样的行为我们称之为多态。我们以真实世界为例,“开车”这种方法,对不同类型的用户要提供不同的參数实现多态,如Car.Drive(Man), Car.Drive(Woman)等。
    • 消息通信(Message Communication):消息通信意味着通过通过消息进行class函数的调用、执行。

    3 多态(Polymorphism)

    在本节,我们分别用代码片段来阐述各自类型的多态类型:函数重载、早期绑定、编译器的多态。

    先创建一个console 工程,并命名为InheritanceAndPolymorphism。然后加入类Overload.cs,再加入DisplayOverload函数。

    public class Overload
        {
            public void DisplayOverload(int a){
                System.Console.WriteLine("DisplayOverload " + a);
            }
            public void DisplayOverload(string a){
                System.Console.WriteLine("DisplayOverload " + a);
            }
            public void DisplayOverload(string a, int b){
                System.Console.WriteLine("DisplayOverload " + a + b);
            }
        }

    Program.cs加入例如以下代码:

    class Program
        {
            static void Main(string[] args)
            {
                Overload overload = new Overload();
                overload.DisplayOverload(100);
                overload.DisplayOverload("method overloading");
                overload.DisplayOverload("method overloading", 100);
                Console.ReadKey();

    执行程序,结果例如以下:

    DisplayOverload 100
    DisplayOverload method overloading
    DisplayOverload method overloading100

    Overload类中的DisplayOverload提供了3类不同的重载函数:方法名同样,參数类型和个数不同。C#中的这样的方式成为重载。既我们不须要为每类函数定义不同名字的函数,仅须要改变函数參数类型和个数就可以实现,这个也成为函数签名。

    用不同的返回值能够否? 我们试试以下的代码:

    public void DisplayOverload() { }
    public int DisplayOverload(){ }

    肯定的结果是,Visual Studio会给予例如以下的报错信息:

    Error: Type 'InheritanceAndPolymorphism.Overload' already defines a member called 'DisplayOverload' with the same parameter types

    从上面的结果可知:返回值不作为多态函数签名。

    我们再执行例如以下的代码:

    static void DisplayOverload(int a)  {   }
    public void DisplayOverload(int a) {   }
    public void DisplayOverload(string a){  }

    结果依旧是报错:

    Error: Type 'InheritanceAndPolymorphism.Overload' already defines a member called 'DisplayOverload' with the same parameter types

    结论:static的可见函数修饰符不作为重载签名。

    执行以下的代码,试试out、ref可否作为重载签名。

    private void DisplayOverload(int a) {   }
    
    private void DisplayOverload(out int a)
            {
                a = 100;
            }
    
    private void DisplayOverload(ref int a) {   }

    结果是例如以下的报错:

    Error: Cannot define overloaded method 'DisplayOverload' because it differs from another method only on ref and out

    结论:ref、out传递參数修饰符也不能作为重载签名。

    4 多态中Params 參数的作用

    一个函数可包括例如以下4种类型的參数传递:

    • 值传递 (pass by value)
    • 引用传递 (Pass by reference)
    • 作为output參数 (As an output parameter)
    • 使用參数数组 (Using parameter arrays)

    我们执行例如以下代码:

    public void DisplayOverload(int a, string a)  {   }
    
            public void Display(int a)
            {
                string a;
            }

    不出意外。获得例如以下报错信息:

    Error1: The parameter name 'a' is a duplicate

    Error2: A local variable named 'a' cannot be declared in this scope because it would give a different meaning to 'a', which is already used in a 'parent or current' scope to denote something else

    在同样的作用域中,參数名称必须是唯一的。

    在Overload.cs文件里,加入例如以下代码:

    public class Overload
        {
            private string name = "Akhil";
    
            public void Display()
            {
                Display2(ref name, ref name);
                System.Console.WriteLine(name);
            }
    
            private void Display2(ref string x, ref string y)
            {
                System.Console.WriteLine(name);
                x = "Akhil 1";
                System.Console.WriteLine(name);
                y = "Akhil 2";
                System.Console.WriteLine(name);
                name = "Akhil 3";
            }
        }

    在Program.cs中加入例如以下代码:

    class Program
        {
            static void Main(string[] args)
            {
                Overload overload = new Overload();
                overload.Display();
                Console.ReadKey();
            }
        }

    执行结果例如以下:

    Akhil
    Akhil 1
    Akhil 2
    Akhil3

    image

    结论:我们通过ref引用传递了name的内存地址。故改动x、y的值相当于直接改动name的值。故结果执行如上。

    以下这段代码演示了paramskeyword的作用:

    在Overload.cs文件加入例如以下代码:

    public class Overload
        {
            public void Display()
            {
                DisplayOverload(100, "Akhil", "Mittal", "OOP");
                DisplayOverload(200, "Akhil");
                DisplayOverload(300);
            }
    
            private void DisplayOverload(int a, params string[] parameterArray)
            {
                foreach (string str in parameterArray)
                   Console.WriteLine(str + " " + a);
            }
        }

    在Program.cs文件加入例如以下代码:

    class Program
        {
            static void Main(string[] args)
            {
                Overload overload = new Overload();
                overload.Display();
                Console.ReadKey();
            }
        }

    执行结果例如以下:

    Akhil 100
    Mittal 100
    OOP 100
    Akhil 200

    C#提供了params动态參数数组机制,很方便的在执行时动态传递不同数量的同类型參数。

    注:params关键词仅能作为函数的最后一个參数适用。

    我们再试试paramskeyword的函数签名和非paramskeyword函数签名的优先级顺序:

    public class Overload
        {
            public void Display()
            {
                DisplayOverload(200);
                DisplayOverload(200, 300);
                DisplayOverload(200, 300, 500, 600);
            }
    
            private void DisplayOverload(int x, int y)
            {
                Console.WriteLine("The two integers " + x + " " + y);
            }
    
            private void DisplayOverload(params int[] parameterArray)
            {
                Console.WriteLine("parameterArray");
            }
    
        }

    Program.cs文件加入例如以下代码:

    class Program
        {
            static void Main(string[] args)
            {
                Overload overload = new Overload();
                overload.Display();
                Console.ReadKey();
            }
        }

    执行结果例如以下:

    parameterArray
    The two integers 200 300
    parameterArray

    从执行结果看。C#很巧妙的进行非params函数的精准匹配优先,如1个int类型3个int类型。则用params类型匹配;2个int类型,用明白定义的函数进行匹配。

    5 结论

    image

    在本节中。我们进行OOP系列的第一篇。主要说明了编译器的多态,它也称为早期绑定或者方法重载。同一时候,我们也学习C#中威力强大的paramskeyword。并用它来实现多态。

    本文要点归纳例如以下:

    • C#函数重载的签名规则是用參数的类型和数量推断,而不是函数的名字。
    • 函数返回值不作为重载签名。
    • 修饰符不作为签名的一部分,如static
    • 同函数中。多个參数名称要唯一
    • ref、out是引用传递。传递的是參数的内存地址
    • params 作为參数关键词。仅能用于函数的最后一个參数

    原文地址:http://www.codeproject.com/Articles/771455/Diving-in-OOP-Day-Polymorphism-and-Inheritance-Ear

  • 相关阅读:
    概要设计说明书
    第二次冲刺——第6天
    第二次冲刺——第5天
    第二次冲刺——第4天
    开发文档
    “来用”Beta版使用说明
    项目总结
    团队站立会议10(第二阶段)
    团队站立会议9(第二阶段)
    团队站立会议8(第二阶段)
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7118553.html
Copyright © 2020-2023  润新知