下面讲讲重要的概念,虚函数和多态。
多态是面向对象程序设计里面非常重要的这个机制。它能很有效的提高程序的可扩充性。
那有些程序设计语言有 被对象继承的概念,但是没有多态的概念,那这样的程序设计语言
只能被称作基于对象的程序设计语言,而不能称为面向对象的语言, 比方说visual
basic就是这样。那说iii之前首先我们给提一下这个虚函数, 虚函数的概念挺简单的,
就是一个成员函数在类里面声明它的时候前面加个virtual关键字,那这个成员函数就称为虚函数。
那为什么关键字只用在类定义里,声明函数的时候?
我们把函数体拿到外面来写的时候呢不要写virtual关键字了,
而且要注意,构造函数和静态成员函数它不能是虚函数。
那虚函数跟普通函数的本质差别实际上就在于虚函数可以参与多态, 而普通的成员函数不能。
那多态呢它有两种表现形式,我们看,第一种表现形式。
第一种表现形式是这样的。首先我们得知道,一个派生类的指针它可以负值给基类指针,对吧,这是赋值兼容规则。
那如果通过基类指针调用基类和派生类中的
同名虚函数的时候,啊,注意,这是虚函数啊,在这种情况下,如果
这个指针指向一个基类的对象,那么被调用的就是基类的虚函数。
如果这个指针指向一个派生类的对象,那么被调用的
就是派生类的虚函数。这样的机制就叫做“多态”。
那这个好像跟我们前面说的有点不一样。那主要差别在哪呢?差别就在于啊,
这个时候被调用的是虚函数,而我们前面说的类似的
通过基类指针调用基类和派生类里面同名的函数
那被执行的就是基类的那个函数,而前面说这个结论的时候呢 那些被调用的函数并不是虚函数。
好这就是多态的第一种表现形式。通过基类的指针来实现的。
那 具体看这个例子。在CBase里面有一个虚函数叫SomeVirtualFunction,
CDerived是从CBase派生出来,它也有一个虚函数,同名虚函数,同参数表达,
也叫SomeVirtualFunction,然后我们在main里面看,我们让一个基类的指针p指向了
这个派生类的对象,然后我们通过基类指针去调用这个同名虚函数SomeVirtualFunction,
那这个时候程序执行到这的时候,
p指向的是哪一个类型的对象, SomeVirtualFunction就是哪一个类的SomeVirtualFunction
在编译的时候是没有办法确定这条语句调用哪一个类的SomeVirtualFunction的,具体到这个程序里面,
当程序走到这条语句的时候,我们看到,p指向的是派生类的对象,CDerived类的对象,
所以这条语句就会执行CDerived类的 SomeVirtualFunction,如果前面的语句不是这样的,
它使得程序走到这的时候p指向的是一个基类,CBase的对象,那么
在此处被调用的就会是基类的SomeVirtualFunction。
这个就是多态的第一种表现形式。多态还有另外一种表现形式,
啊我们知道派生类的对象可以赋值给基类引用,然后我们通过基类的引用可以调用
基类和派生类中的同名虚函数,在这种情况下,通过这个引用,
引用的是一个基类的对象,那么被调用的就是基类的虚函数。啊如果这个引用引用的是一个派生类的对象,
那么被调用的就是派生类的虚函数。这种机制也叫做多态。看这个例子。
CBase和CDerived里面都有同名虚函数SomeVirtualFunction,啊,然后在main里面呢
我们让一个CBase基类的引用了一个派生类的对象, 那么当程序走到这条语句的时候
由于这个r引用的是一个派生类的对象,
所以此时被调用的就是派生类的SomeVirtualFunction。但实际上这条语句是多态,
如果前面的代码不是这样的,当程序走到这的时候如果r引用了
基类的对象,那么此时被调用的就会是基类的SomeVirtualFunction了。
再看一个多态的简单例子。这里有class A,
它有虚函数Print,它输出A::Print,那class
B,从A派生而来, 它也有虚函数Print,输出B::Print,下面这个class
D,它也从A派生而来, 它的Print当然就输出D::Print,然后class
E呢又是从B派生而来,它的Print输出E::Print,
呃,这四个类的关系是这样的。其中这个E呢是A的一个间接派生类。
那我们看在main里面,一开始我们定义的若干个对象,
初始化了若干个指针,从这些对象的名字和指针的名字上就能看出他们的这个类型, 然后我们来让pa->Print(),
这条语句执行的是哪一个类的Print呢?啊我们要注意到这条语句实际上它是多态,
为什么啊,因为pa是基类的指针,啊,Print是基类和各个派生类里面都有的
同名虚函数,所以这条语句就是多态。那就要看pa这个时候指向的到底是哪一个类的对象了。
那我们看到,程序走到这的时候pa指向的是什么,是class A的对象,
因此说这条语句的输出结果就是调用了class A的Print输出这个
A::Print,然后我们让pa=pb 那这时候pa呢就指向了这个class
B的对象, 所以接下来的这条语句根据多态的原则,就应该执行class
B的Print, B::Print,接下来我们让这个pa=pd,那这时候pa呢就指向了一个class
D的对象, 那么下面再输出,呃,再调用main的时候当然就调用class
D的Print, 然后呢再让pa=pe,这时候pa指向一个class
E的对象, 那class E呢它是class A的间接派生类,那么这个
多态的原则在这条语句仍然适用,所以就可以输出class
E的这个 Print,那多态到底有什么用呢?多态前面已经说了它能够很有效的提高程序的这个可扩充性,
什么叫可扩充性呢?就是当一个程序需要 修改或者增加新的功能的时候,你这个程序
所做的改动或者所做的增加量比较少,那你这个程序的可扩充性就是好的。