C#面向对象(OOP)入门—第一天—多态和继承(方法重载)
面向对象是什么
面向对象是一种基于对象的编程方法,它取代了仅仅依靠方法和流程的编程方式。面向对象的编程语言中,对象(object)其实就是指特定类型、或某个类的实例。面向对象使得编程人员更容易组织和管理整个软件的程序。对象之间的独立性使得我们更容易更新和更改程序。对于大型程序则更加易读和易管理。
面向对象包含哪些内容
- 数据抽象(Data Absraction):数据抽象的概念是逻辑实现的内部和多余的细节对用户隐藏。用户可以使用一个类所允许使用的任何数据和方法,而不必要明白它是如何创建或者它背后有多么复杂。举一个现实的例子,就是开车过程中,我们可以通过换挡杆来换档,然而我们比不要知道他是如何换挡的,比如换挡过程中齿轮箱等部件是如何动作的,我们只需要根据自己的需要来切换档位就行。
- 继承(Inheritance):继承是面向对象中最受欢迎的概念,继承让开发者可以实现代码重用。例如,我们在一个类里面实现了一个有特定逻辑功能的函数,我们可以用这个类派生一个新的类,然后我们不必要重新写这个函数,在派生类中可以直接使用。
- 数据封装(Data Encapsulation):将类里面的成员函数和成员数据封装进一个单独的模块叫做封装,数据或函数的可见性可以由访问修饰符来控制。
- 消息通讯(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 相同)。
参数数组参数在多态中的作用
一个方法被调用过程中,参数的类型有以下几种:
- 传递值
- 传递引用(ref)
- 作为输出参数(out)(其实也是一种引用的传递)
- 采用参数数组(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/
我只是在作者基础上进行了翻译以及总结,并加了一点自己的理解,希望对大家有帮助。
如有错误,敬请指证。
C#面向对象(OOP)入门—第一天—多态和继承(方法重载)的更多相关文章
- C#面向对象(OOP)入门—第二天—多态和继承(继承)
介绍: 第一天的内容主要是不同情形下的方法重载.这一部分则主要讲面向对象中继承的概念.首先用一个要点图形来定义继承. 继承 一个简单的例子: ClassA: class ClassA:ClassB { ...
- 深入理解OOP(第一天):多态和继承(初期绑定和编译时多态)
在本系列中,我们以CodeProject上比较火的OOP系列博客为主,进行OOP深入浅出展现. 无论作为软件设计的高手.或者菜鸟,对于架构设计而言,均需要多次重构.取舍,以有利于整个软件项目的健康构建 ...
- 深入浅出OOP(一): 多态和继承(早期绑定/编译时多态)
在本系列中,我们以CodeProject上比较火的OOP系列博客为主,进行OOP深入浅出展现. 无论作为软件设计的高手.或者菜鸟,对于架构设计而言,均需要多次重构.取舍,以有利于整个软件项目的健康构建 ...
- 深入理解OOP(四): 多态和继承(抽象类)
在本文中,我们讨论OOP中的热点之一:抽象类.抽象类在各个编程语言中概念是一致的,但是C#稍微有些不一样.本文中我们会通过代码来实现抽象类,并一一进行解析. 深入理解OOP(一):多态和继承(初期绑定 ...
- 深入浅出OOP(二): 多态和继承(继承)
本文是深入浅出OOP第二篇,主要说说继承的话题. 继承的介绍 在OOP中,继承有如下的定义: 继承是一种OOP的机制,用于派生继承预定义的类 在这个继承关系中,预定义的类是基类,新类是子类 继承常常用 ...
- 深入浅出OOP(三): 多态和继承(动态绑定/运行时多态)
在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 运行时多态或迟绑定.动态绑定 在C#语音中,运行时 ...
- 深入浅出OOP(四): 多态和继承(抽象类)
在本文中,我们讨论OOP中的热点之一:抽象类.抽象类在各个编程语言中概念是一致的,但是C#稍微有些不一样.本文中我们会通过代码来实现抽象类,并一一进行解析. Abstract Classes 在微软的 ...
- PHP面向对象(OOP):把对象串行化serialize()方法,__sleep()方法,__wakeup()方法
有时候需要把一个对象在网络上传输,为了方便传输,可以把整个对象转化为二进制串,等到达另一端时,再还原为原来的对象,这个过程称之为串行化(也叫序列化), 就像我们现在想把一辆汽车通过轮船运到美国去,因为 ...
- Java之面向对象例子(三) 多态,重写,重载,equals()方法和toString()方法的重写
重写(继承关系) 子类得成员方法和父类的成员方法,方法名,参数类型,参数个数完全相同,这就是子类的方法重写了父类的方法. 重载 在一个类里有两个方法,方法名是完全一样的,参数类型或参数个数不同. 例子 ...
随机推荐
- ubuntu安装记录——安装作业部落cmd markdown
安装这个折腾了一个多小时,,,, 表示是因为印象笔记没有markdown才买的作业部落cmd markdown的会员,,,,然而刚刚随意一看发现印象笔记出markdown了,,,,, 还是记录一下安装 ...
- axios请求,拦截器的使用
1. axios 创建请求 import axios from 'axios' import {Message} from 'element-ui' import router from " ...
- POJ2774:Long Long Message——题解
http://poj.org/problem?id=2774 给定两个字符串 A 和 B,求最长公共子串. 论文题,把两个串合并起来,比较两个串各自的后缀的height值取最大即可. #include ...
- Vue_WebPack小白入门
Vue语法笔记 Vue项目搭建过程 Vue问题总结 去掉vue 中的代码规范检测(Eslint验证) 解决跨域请求问题 Vue推荐资料
- bzoj2276: [Poi2011]Temperature(单调队列/堆)
这题有两种写法,而且是完全(几乎?)不一样的写法...并不是换了个方法来维护而已 单调队列O(N):用一个队列维护a[]的单调递减,对于每个i满足a[队头]<=b[i],然后就可以算出以每一位为 ...
- 破解wingide编辑器
先到官网下载最新版的wingide(我下载的是5.1.11-1),然后安装,打开,出现下面的界面时选第三个,然后输入“ENX27-HWM6G-XYVFA-165PG”,如下图所示: 接下来你软件会给你 ...
- 第六章 指针与const
const一词在字面上来源于常量constant,const对象在C/C++中是有不同解析的,如第二章所述,在C中常量表达式必须是编译期,运行期的不是常量表达式,因此C中的const不是常量表达式:但 ...
- Spring框架介绍和原理
SpringMVC框架介绍 1) Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功 ...
- FreeRTOS - 任务使用注意
如果使用xTaskCreate() 创建任务,任务栈使用的是FreeRTOS heap
- leetcode 刷题日志 2018-3-28
树: 404. 左叶子之和 求所有左叶子结点之和 . 递归法 分析:递归法遍历结点,找左叶子结点 空指针判断 有左子节点?是叶子结点?是的话更新value的值 int sumOfLeftLeaves( ...