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()方法的重写
重写(继承关系) 子类得成员方法和父类的成员方法,方法名,参数类型,参数个数完全相同,这就是子类的方法重写了父类的方法. 重载 在一个类里有两个方法,方法名是完全一样的,参数类型或参数个数不同. 例子 ...
随机推荐
- [六省联考2017]分手是祝愿 期望DP
表示每次看见期望的题就很懵逼... 但是这题感觉还是值得一做,有可借鉴之处 要是下面这段文字格式不一样的话(虽然好像的确不一样,我也不知道为什么,是直接从代码里面复制出来的,因为我一般都是习惯在代码里 ...
- 洛谷 P1291 [SHOI2002]百事世界杯之旅 解题报告
P1291 [SHOI2002]百事世界杯之旅 题目描述 "--在2002年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字.只要凑齐所有百事球星的名字,就可参加百事世界杯之旅的抽 ...
- 洛谷 P1108 低价购买 解题报告
P1108 低价购买 题目描述 "低价购买"这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:"低价购买:再低价购买&quo ...
- [LOJ 6159] 最长树链
看到要求gcd不为1所以肯定在这条答案链上都是一个质数的倍数,所以就会产生一个很暴力的想法 没错,正解就是这样的暴力 只让走是i(素数)倍数的点,作最长链 最长链可以树形dp或两遍bfs,一遍找端点, ...
- codeforces的dp专题
1.(467C)http://codeforces.com/problemset/problem/467/C 题意:有一个长为n的序列,选取k个长度为m的子序列(子序列中不能有位置重复),求所取的k个 ...
- 读取proc/uptime信息。
#include <stdio.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h ...
- 如何按需动态加载js文件
JavaScript无非就是script标签引入页面,但当项目越来越大的时候,单页面引入N个js显然不行,合并为单个文件减少了请求数,但请求的文件体积却很大.这时候最好的做法就是按需引入,动态引入组件 ...
- TCP的连接(三次握手)和释放(四次挥手)
1 http都设置哪些header? http协议规定:一个完整的客户端发送给服务端的HTTP请求包括: (1)请求行:包括了请求方法.请求资源路径.HTTP协议版本,eg:GET/Server/im ...
- linux下输出查看进程及杀进程
1.查找有关tomcat的进程 ps -ef | grep tomcat 2.查看某端口占用情况 netstat -tulpn | grep 9009 3.杀进程 普通:kill 进程id 强制:ki ...
- 【C++ STL】List
1.结构 list使用一个double linked list(双向链表)来管理元素. 2. list 能力 list内部结构和vector或deque截然不同,所以与他们的区别: list不支持随机 ...