面向对象语言三大特性:封装、继承、多态
函数重载和运算符重载实现静态多态性。抽象类和虚方法共同实现动态多态性。
在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。
1、重载(overload): 在同一个作用域(一般指一个类)的两个或多个方法函数名相同,参数列表不同的方法叫做重载,它们有三个特点(俗称两必须一可以):
• 方法名必须相同
• 参数列表必须不相同
• 返回值类型可以不相同
例如:
public void Test()
{
Console.WriteLine("睡觉");
}
public int Test(int time)
{
Console.WriteLine("{0}点睡觉",time);
return time;
}
2、重写(override): 只有基类成员声明为virtual或abstract时,才能被派生类重写,而如果子类想改变虚方法的实现行为,则必须使用override关键字。它的特点是(三个相同):
• 相同的方法名
• 相同的参数列表
• 相同的返回值
例如:
public class you
{
public virtual void talk()
{
Console.WriteLine("one");
}
}
public class my : you
{
public override void talk()
{
Console.WriteLine("two");
}
}
小结一下重载和重写的区别:
区别 \ 名称 | 重载 | 重写 |
---|---|---|
范围 | 同一个类 | 不同的类 |
方法名 | 相同 | 相同 |
参数列表 | 不同 | 相同 |
修饰符 | 无关 | 大于父类方法 |
抛出父类没有的异常 | 可以 | 不可以 |
返回类型 | 不同 | 相同 |
与面向对象 | 多态 | 继承 |
3、抽象类(abstract): 在基类中定义的并且必须在派生类中重写的方法,使用 abstract 关键字定义,如
//包含抽象函数的类,类也必须定义为抽象的(抽象函数只能在抽象类中定义)
public abstract class Biology
{
public abstract void Live();//抽象函数不能有函数体,且修饰符必须是 public
void Talk()//抽象类中可以包含普通函数
{
}
}
public class Animal : Biology
{
public override void Live()
{
Console.WriteLine("Animal重写的抽象方法");
}
}
注意:可以声明抽象类的对象。但是不可以实例化对象。必须依靠子类来实例化。
public abstract class Test
{
public abstract void Attack();
}
public class Boss : Test
{
public override void Attack()
{
}
}
class Program
{
static void Main(string[] args)
{
Boss b = new Boss();
b.Attack();
}
}
4、虚方法(virtual): 即为基类中定义的允许在派生类中重写的方法,使用 virtual 关键字定义,如
public class Test
{
public virtual void talk()
{
Console.WriteLine("one");
}
}
注意:虚方法也可以被直接调用
Test t = new Test();
t.talk();
virtual (虚方法) 和 abstract (抽象方法) 的区别
virtual 和 abstract 都是用来修饰父类的,通过覆盖父类的定义,让子类重新定义。
5、隐藏方法: 如果签名相同的方法在基类和派生类中都进行了声明,但是该方法没有分别声明为virtual和override,派生类就会隐藏基类方法。(要使用new关键字进行声明)
public class Student
{
public virtual void Exam()
{
Console.WriteLine("学生都要考试");
}
}
public class Undergraduate:Student
{
public new void Exam()
{//隐藏方法
base.Exam();
Console.WriteLine("大学生有选择考试科目的权利");
}
}
注意:
(1)隐藏方法不但可以隐藏基类中的虚方法,而且也可以隐藏基类中的非虚方法。
(2)隐藏方法中父类的实例调用父类的方法,子类的实例调用子类的方法。
(3)重写方法中子类的变量调用子类重写的方法,父类的变量要看这个父类引用的是子类的实例还是本身的实例。如果引用的是父类的实例,那么调用基类的方法;如果引用的是派生类的实例,则调用派生类的方法。
虚方法的调用: 调用上,使用子类构造的对象调用虚方法,就会调用子类的方法,使用父类构造的对象,就会调用父类的方法。
隐藏方法的调用: 调用上, 使用子类类型的声明调用隐藏方法,就会调用到子类的方法。若想调用被隐藏的方法,需要用父类类型的声明来调用。