C#面向对象(OOP)入门—第一天—多态和继承(方法重载)

面向对象是什么

面向对象是一种基于对象的编程方法,它取代了仅仅依靠方法和流程的编程方式。面向对象的编程语言中,对象(object)其实就是指特定类型、或某个类的实例。面向对象使得编程人员更容易组织和管理整个软件的程序。对象之间的独立性使得我们更容易更新和更改程序。对于大型程序则更加易读和易管理。

 

面向对象包含哪些内容

  1. 数据抽象(Data Absraction):数据抽象的概念是逻辑实现的内部和多余的细节对用户隐藏。用户可以使用一个类所允许使用的任何数据和方法,而不必要明白它是如何创建或者它背后有多么复杂。举一个现实的例子,就是开车过程中,我们可以通过换挡杆来换档,然而我们比不要知道他是如何换挡的,比如换挡过程中齿轮箱等部件是如何动作的,我们只需要根据自己的需要来切换档位就行。
  2. 继承(Inheritance):继承是面向对象中最受欢迎的概念,继承让开发者可以实现代码重用。例如,我们在一个类里面实现了一个有特定逻辑功能的函数,我们可以用这个类派生一个新的类,然后我们不必要重新写这个函数,在派生类中可以直接使用。
  3. 数据封装(Data Encapsulation):将类里面的成员函数和成员数据封装进一个单独的模块叫做封装,数据或函数的可见性可以由访问修饰符来控制。
  4. 消息通讯(Message Communication):指当一个对象调用一个类的方法去执行的时候,消息的通讯手段。

 

方法重载(编译时多态)

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);
      }
  }

 类似上面的代码,3个函数拥有相同的名字,但是参数类型不同。这就是方法重载。

知识点:在C#中,函数签名(识别一个函数的依据)包括函数的名称以及函数的参数(包括参数数量和参数数据类型,参数的类型)。函数的返回值不是,函数的修饰关键字(比如static)也不是。参数的类型指的是ref或者out的参数。(例如 int a 和 ref int a不同,但是注意 ref int a 和 out int a 相同)。

参数数组参数在多态中的作用

一个方法被调用过程中,参数的类型有以下几种:

  1. 传递值
  2. 传递引用(ref)
  3. 作为输出参数(out)(其实也是一种引用的传递)
  4. 采用参数数组(params)

当我们传递N个(未知)参数给某个方法的时候,我们可以用params关键字。

知识点:params关键字只能在方法的最后一个参数,并且数组不能是多维的。

例如如下定义是错误的:

private void DisplayOverload(int a, params string[] parameterArray, int b) {  }

 知识点:当有个params的参数在最后一个,但是倒数第二个参数的类型和最后一个相同,则传递参数中,符合类型的第一个会给值,剩余的给后面的参数数组(例如 []和[][]可以,而[,] 不可以),并且params关键字不能和ref或out组合使用。

例如:

public class Overload
{
    public void Display()
    {
        DisplayOverload(100, 200, 300);   //100会传递给参数a,200和300传递给parameterArray
        DisplayOverload(200, 100);  //200传递给参数a,100传递给parameterArray
        DisplayOverload(200);  //200传递给参数a
    }

    private void DisplayOverload(int a, params int[] parameterArray)
    {
        foreach (var i in parameterArray)
            Console.WriteLine(i + " " + a);
    }

}

 这种情况也是错误的

public class Overload
    {
        public void Display()
        {
           string [] names = {"Akhil","Arsh"};
           DisplayOverload(2, names, "Ekta");  //当调用函数时,编译器会试图将names和 "Ekta"组合为一个字符串数组,但是names不是string而是string[]类型,所以会报错
        }

        private void DisplayOverload(int a, params string[] parameterArray)
        {
            foreach (var str in parameterArray)
                Console.WriteLine(str + " " + a);
        }

    }

 对于在传递数组参数后,改变其值会发生什么举如下两个例子:

例子1:

public class Overload
    {
        public void Display()
        {
            int[] numbers = {10, 20, 30};
            DisplayOverload(40, numbers);
            Console.WriteLine(numbers[1]);
        }

        private void DisplayOverload(int a, params int[] parameterArray)
        {
            parameterArray[1] = 1000;
        }

    }

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

//输出结果是1000

 例子2:

public class Overload
    {
        public void Display()
        {
            int number = 102;
            DisplayOverload(200, 1000, number, 200);
            Console.WriteLine(number);
        }

        private void DisplayOverload(int a, params int[] parameterArray)
        {
            parameterArray[1] = 3000;
        }

    }

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

//输出结果是102

 例子1中的数组传递到函数里面,在函数更改值对应也更改了原数组的值。(我认为是传递的数组的地址);但是对于例子2,不得不新建一个数组来存放各个参数组成的新数组,然后传递到调用的函数里,当对其更改值时,其实更改的是新数组对应的值,而这个函数对number的值一无所知,跟别提去更改了。

另一种重载的情况

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");
        }

    }

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

/*
输出是:
parameterArray
The two integers 200 300
parameterArray
*/

 第一个和第三个调用没有问题,只能调用带数组的参数。但是对于第二种我不太理解,原文作者解释说,C#很聪明,他对params参数不太认可,就像不是自己的亲生孩子一样,所以作为第二选择,两个int参数正好有匹配的函数来调用,所以这样输出。作者虽然感情化的描述了,但是可以理解,因为确实就是这样的机制。要想真正的明白缘由,或许还要查阅一些资料才能明白,暂时搁置这个问题吧。

好吧,一个更有趣的例子:

public class Overload
    {
        public static void Display(params object[] objectParamArray)
        {
            foreach (object obj in objectParamArray)
            {
                Console.Write(obj.GetType().FullName + " ");
            }
            Console.WriteLine();

        }
    }

class Program
    {
        static void Main(string[] args)
        {
            object[] objArray = { 100, "Akhil", 200.300 };
            object obj = objArray;
            Overload.Display(objArray);
            Overload.Display((object)objArray);
            Overload.Display(obj);
            Overload.Display((object[])obj);
            Console.ReadKey();

        }
    }

/*
输出结果是:
System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double
*/

 Display函数是输出数组内每个成员的类型。第一个调用没有问题,第二个调用与第三个调用等价,传递过去的其实是一个object对象(注意这不是装箱,装箱时值类型转换为object,而数组是引用类型),这时,首先是将object转换为object[]但是不存在这样的默认转换,所以只能创建一个object[]来存放obj,而obj的类型就是object[],所以输出System.Object[]。第四个调用,做了强制的转换,从object到object[],所以跟第一个相同。

总结:

这篇文章主要讲了编译时多态,也叫作前期绑定或者方法重载。并列举了方法重载的各种情形,以及params参数在重载中的特殊用途。

  • C# 通过参数名字来区别一个方法
  • 方法返回值和参数类型绝方法签名一部分如果方法名称相同所以多态性
  • 修饰符(如static)方法签名一部分
  • 方法签名包括名称 形参的数量和类型一个函数返回类型签名一部分两种方法具有相同签名并且成员也不能有同名的成员。
  • 参数名称唯一我们可以一个参数名称声明变量名称相同功能相同
  • 如果通过传递变量传递过去如果通过 ref out引用地址传递过去
  • params 关键字只能应用方法最后一个参数因此n 个数量的参数可以最后
  • C# 聪明承认如果倒数第二个参数参数相同数据类型
  • 参数数组必须数组

注明:原文地址:https://codeteddy.com/2014/05/11/diving-in-oop-part-1-polymorphism-and-inheritanceearly-bindingcompile-time-polymorphism/

我只是在作者基础上进行了翻译以及总结,并加了一点自己的理解,希望对大家有帮助。

如有错误,敬请指证。

posted @ 2017-03-19 12:00  Dean-Feng  阅读(402)  评论(0编辑  收藏  举报
Bolg of 冯广乐