(1)概述
如果要隐藏函数,要使用new关键字;如果要重写(覆盖)虚函数,要使用virtual和override关键字。
然后讲一下什么是申明类和实例类。举个例子: Bird b = new Magpie();
Bird类就是申明类,而Magpie就是实例类。
接下来讲一下调用某个对象的函数的基本规律。该方法可以结合以下几节的实例具体运用。
1、当调用一个对象的函数时,系统会直接去检查这个对象的申明类,看所调用的函数是否为虚函数;
2、如果不是虚函数,那么它就直接执行该函数。而如果有virtual关键字,也就是一个虚函数,那么这个时候它就不会立刻执行该函数了,而是转去检查对象的实例类。
3、在这个实例类里,他会检查这个实例类的定义中是否有重新实现该虚函数(通过override关键字),如果是有,那么OK,它就不会再找了,而马上执行该实例类中的这个重新实现的函数。而如果没有的话,系统就会不停地往上找实例类的父类,并对父类重复刚才在实例类里的检查,直到找到第一个重写了该虚函数的父类为止,然后执行该父类里重写后的函数。
该规律节选自 http://blog.csdn.net/shamozhu/article/details/3835664
(2)隐藏函数:
class Program
{
static void Main(string[] args)
{
Bird b = new Bird();
b.Chirp();
Magpie m = new Magpie();
m.Chirp();
Bird b2 = new Magpie();
b2.Chirp();
}
}
class Bird
{
public void Chirp()
{
Console.WriteLine("...");
}
}
class Magpie : Bird
{
public void Chirp()
{
Console.WriteLine("Magpie ...");
}
}
如果想在Magpie类中定义自己的Chirp()方法,也就是说隐藏基类中的同样签名的方法,就需要在派生类中定义相同签名的方法。
但是这样编译器会出现一个警告,提示如果有意去隐藏基类的方法,请使用New关键字修饰。
Warning 1 'InheritanceTest.Magpie.Chirp()' hides inherited member 'InheritanceTest.Bird.Chirp()'. Use the new keyword if hiding was intended.
所以正确的做法是
class Magpie : Bird
{
public new void Chirp()
{
Console.WriteLine("Magpie ...");
}
}
如果运行该程序,结合概述中的规律,在调用对象的方法时,查看申明类的方法的声明,如果不是虚函数,则直接执行申明类中的方法。
所以在上面那个例子中,输出结果为
...
Magpie ...
...
只有第二次调用的时候使用的是Magpie类作为申明类,所以只有第二次调用的是Magpie.Chirp()的方法
(3)虚函数
下面在Bird.Chirp()方法前加上virtual关键字,则该函数成为了虚函数。
class Program
{
static void Main(string[] args)
{
Bird b = new Bird();
b.Chirp();
Magpie m = new Magpie();
m.Chirp();
Bird b2 = new Magpie();
b2.Chirp();
}
}
class Bird
{
public virtual void Chirp()
{
Console.WriteLine("...");
}
}
class Magpie : Bird
{
public void Chirp()
{
Console.WriteLine("Magpie ...");
}
}
在以上的例子中,Magpie类的定义方法会使编译器发出警告,对Magpie.Chirp()方法或者使用new关键字,或者使用override关键字。
Warning 1 'InheritanceTest.Magpie.Chirp()' hides inherited member 'InheritanceTest.Bird.Chirp()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
下面我们使用new关键字来隐藏父类中的方法,然后看看输出结果是什么。
class Magpie : Bird
{
public new void Chirp()
{
Console.WriteLine("Magpie ...");
}
}
运行程序,输出结果为:
...
Magpie ...
...
道理同我们在概述中一样。申明类为Bird时,虽然Chirp()是虚函数,但是子类中并没有重写该函数,所以最后还是执行了Bird.Chirp()的方法。申明类为Magpie时,就直接执行了Magpie.Chirp()的方法。
如果我们要使用override关键字,就表示我们要对父类中的虚函数重写或者覆盖。
class Magpie : Bird
{
public override void Chirp()
{
Console.WriteLine("Magpie ...");
}
}
再运行程序,就会得到不同的结果:
...
Magpie ...
Magpie ...
具体原因请结合概述中的规律进行分析。
(4)下面做一个练习
class Program
{
static void Main(string[] args)
{
Animal animal = new Animal();
Animal bird = new Bird();
Animal magpie = new Magpie();
Animal chicken = new Chicken();
Chicken c2 = new Chicken();
animal.Move();
bird.Move();
magpie.Move();
chicken.Move();
c2.Move();
}
}
class Animal
{
public virtual void Move()
{
Console.WriteLine("Animal move");
}
}
class Bird : Animal
{
public override void Move()
{
Console.WriteLine("Bird move");
}
}
class Magpie : Bird
{ }
class Chicken : Animal
{
public new void Move()
{
Console.WriteLine("Chicken move");
}
}
输出结果为:
Animal move
Bird move
Bird move
Animal move
Chicken move