浅谈继承

引言

     面向对象的三大利器:封装,继承,多态,正是因为这三个主要特性,演化出了众多优秀的设计模式和框架,只有掌握了它们才能真正掌握面向对象。本文主要探讨继承的概念,都是些简单的语法,但是可能很多人在学习了若干框架、模式后,反而忘记或者说淡忘了一些基本的概念,笔者就是其中一个,故写下此文,一方面温故而知新,另一方面也强调基础的重要性。

概念

     继承就是在类之间建立一种相交关系,使得新定义的派生类的实例可以继承已有的基类的特征和能力,而且可以加入新的特性或者是修改已有的特性建立起类的新层次。我们知道,现实中的事物都是有其相似和区别的,如果我们将相似的特征提取出来集中描述,不同的特征分别描述并包括那些相同的特征,那就是一个典型的继承。相似的特征我们可以构造一个基类封装起来,而对于那些有区别的特征,我们可以构建不同的子类封装并继承基类,从而扩展或重定义基类的行为。

基础语法

     下面我想通过一些例子,探讨和总结继承的应用规则,示例代码如下:

场景一:

Code

     代码很简单,定义了一个基类BaseClass,包含一个无参构造函数,一个SayHello方法;子类ChildClass继承基类,但是不定义任何方法;Test类用于测试,创建一个ChildClass的实例,并调用SayHello方法,输出结果如下:  

     Base Class Constructor   

     Hello, everyone, I'm base class.

结论:在ChildClass中,我们没有定义任何的成员,只是继承BaseClass,但是却能调用父类的SayHello方法,并且从结果我们可以看出,整个的调用过程如下:第一步,实例化ChildClass,虽然我们没有定义它的构造函数,但是对于任何类,都有一个默认的构造函数,也就是说ChildClass中实际有这样一个构造函数:public ChildClass() { };通过输出结果,我们可以看出,ChildClass的构造函数实际调用了BaseClass的构造函数; 第二步,调用child实例的SayHello方法,很明显该方法是继承自BaseClass的。

场景二:

     下面对ChildClass做一些小的修改,添加一个无参构造函数,添加一个SayHello方法,由于跟父类的方法重名了,故需要在SayHello前面加了个new关键字,用来表示隐藏基类的方法,不然编译器会报警,具体代码如下:

Code

输出结果如下:   

     Base Class Constructor

     Child Class Constructor

     Hello, everyone, I'm child class.

结论:1 验证了前面说的,实例化的时候,会先调用父类构造函数,然后再调用子类构造函数;2 如果定义一个与父类重名的方法,会隐藏父类的方法而不会覆盖父类的方法,我们可以做个实验,修改Main方法如下:

Code

实例化一个ChildClass后,将对象指向BaseClass的引用,输出结果如下:  

     Base Class Constructor

     Child Class Constructor

     Hello, everyone, I'm base class.

 由此可见,如此调用的是基类的SayHello方法。

场景三:

     修改BaseClass和ChildClass,添加关键字 virtual 和 override,具体代码如下:

Code

将BaseClass的SayHello方法定义为虚方法,并在ChildClass中重写它,在Main方法中,实例化一个ChildClass对象,指向BaseClass的引用,并调用SayHello方法,输出结果如下:

     Base Class Constructor     

     Child Class Constructor

     Hello, everyone, I'm child class.

结论:如果用 virtual 和 ovrride关键字在父类中申明虚拟方法并在子类中重写,那么重写的方法将会覆盖父类的方法(注意对比前面用new关键字隐藏父类方法的例子),这样即便child变量指向的是BaseClass的引用实际调用的也是ChildClass的方法。

场景四:

     在场景三的基础上修改BaseClass如下:

Code

即修改BaseClass的构造函数为有参构造函数,这时候编译将会出错,提示说BaseClass不含有无参构造函数;有此我们可推断出以下几点:1 如果定义一个有参构造函数,将会覆盖默认的无参构造函数;2 如果子类含有无参构造函数,那么父类一定要含有无参构造函数,真的是这样吗?为了验证我们的想法,接着在BaseClass中添加一个无参构造函数,代码如下:

Code

输出结果与场景三一致,这似乎验证了前面的猜测,那么试一下以下代码:

 

Code

 

输出结果如下:

  Base Class Constructor test  

     Child Class Constructor

     Hello, everyone, I'm child class.

可以看出,虽然父类没有无参构造函数,但只要子类无参构造函数显示调用了父类的有参构造函数,同样可以完成子类的实例化,由此我们可以做出结论:子类实例化之前必须先实例化父类,既可以通过隐式调用父类无参构造函数(所谓隐式,就是指编译器自动完成),也可以通过显式调用父类构造函数完成。

 

总结

     前面通过四个场景简单描述了继承的概念,主要有以下几点:

     1 子类实例化的时候必须先调用父类的构造函数,默认会调用它的无参构造函数;

     2 如果父类没有定义无参构造函数,子类构造函数必须显式地调用父类的有参构造函数;也就是说,子类实例化之前,必须先实例化父类。

     3 如果子类出现了与父类同名的方法,并且没有用virtual override重写,那么将会隐藏而不会覆盖父类的方法;

     4 如果子类用override关键字重写了基类的virtual方法,那么子类的方法将会覆盖基类的方法。

posted @ 2008-11-28 22:30  lemonade  阅读(283)  评论(0编辑  收藏  举报