在人类最初的时候,大家都是用手吃饭的,但是随着人类的漫长发展,渐渐的开始出现等级制度,部落,再之后,就是国家。每个国家的人吃饭的方式都不一样,英国人用刀叉吃饭,中国人用筷子吃饭。所以,如果想用程序来表现就是,现有一个基类(父类),
class Human { public: void eating( void ) { cout << "use hand to eat" << endl; } };
接着,在父类的基础上,诞生了派生类,英国人,中国人,
class Englishman : public Human { public: //覆写 void eating(void) { cout << "use knife to eat" << endl; } }; class Chinese : public Human { public: void eating(void) { cout << "use chopstick to eat" << endl; } };
子类继承了父类的函数,并对其进行修改,当然只是修改函数的内容,并没有修改函数的返回值类型,函数名,函数参数,这种叫做函数的“覆写”。那么,我现在在global space区域实现一个函数,
void test_eating(Human& h) { h.eating(); }
接着,我在主函数中,创建三个对象,
Human h; Englishman e; Chinese c;
然后,我去调用这个test_eating()函数,
test_eating(h); test_eating(e); test_eating(c);
那么,输出结果会是什么呢?
很明显,这不是我们想要的结果,我们明明创建了Englishman对象,Chinese对象,调用test_eating()函数时,却无法输出自己类内部的函数。为了解决这一问题,我们只要在父类中,对
void eating( void )
这个函数,把它变为虚函数就行了。只要在函数前加上virtual。实现方式如下:
virtual void eating( void )
对于这种做同一件事,处理的方式却不同,这种在C++中被称作是“多态”。也就是说,采用相同的调用方法,对于不同的对象,会调用不同的类里面的函数。
当我们把eating函数变为虚函数的时候,我们的目的就达成了。
那么多态采用的是什么样的一种机制呢?对于一般的函数,也就是非虚函数,采用的是静态联编,也就是说,非虚函数,在编译时就确定好了要调用哪个函数。而对于动态联编,是在运行时才确定调用的是哪一个函数。那么动态联编是如何做到的呢?当一个类内有虚函数时,基于这个类所创建的对象内部都会有一个指针,这个指针指向了虚函数表,当我们调用函数时,就会根据这个指针找到虚函数表,从而调用虚函数。
那么多态的使用有没有什么特点呢?1.如果调用函数时,传的是值,那么就没有多态,只有传的是指针或引用才会有多态。传值时只能是静态联编。2.只有类的成员函数才能声明为虚函数。3,静态成员函数不能是虚函数。4.内联函数不能是虚函数。5.构造函数不能是虚函数。6.析构函数一般都声明为虚函数。7.重载函数不可设置为虚函数。
有个很关键的一点就是,如果要把函数设置为虚函数,那么,就得保证函数名相同,函数参数列表相同,函数返回值也应该相同。代码如下:
class Person { public: virtual void test( void ) { cout << "Human test() " << endl; } } class Englishman { public: virtual void test( void ){ cout << "Englishman test()" << endl; } } class Chinese { public: virtual void test( void ){ cout << "Chinese test()" << endl; } }
这个时候,设置为虚函数完全是可以的。当然也有例外。就是,可以函数返回值不同。函数的返回值类型跟它的类的类型完全相同,是它的类的指针或引用。代码如下:
class Person { public: virtual Person* test( void ) { cout << "Human test() " << endl; return this; } } class Englishman { public: virtual English* test( void ){ cout << "Englishman test()" << endl; return this; } } class Chinese { public: virtual Chinese test( void ){ cout << "Chinese test()" << endl; return this; } }
这样做是完全可以的。
本文出自 “梵高说我脑子有病” 博客,请务必保留此出处http://chen0547.blog.51cto.com/12489941/1979398
原文地址:http://chen0547.blog.51cto.com/12489941/1979398