类似LINUX内核驱动子系统,如下面的示意代码:
if(fb->open) fb->open();当我们从更底层对fb->open()进行封装了的时候,对应的系统调用不再是系统默认的,而是调用到我们更底层的fb->open.
这个C++里面的多态思维有点相仿.如果基类和其派生类都定义了相同(部分相同)的一个方法的话,我们可以选择调用基类或其派生类的一个方法.
C++的多态主要分两个方面:编译时和运行时,两者分别对应着重载和覆盖.
重载:
载函数必须具有不同的参数个数,或不同的参数类型.仅返回值不同时,不能定义为重载函数.
源码:
#include <iostream> class simpleClass { public: void func(char); void func(int); void func(int,int); }; void simpleClass::func(char a) { std::cout << "funcChar" << std::endl; } void simpleClass::func(int i) { std::cout << "funcInt" << std::endl; } void simpleClass::func(int i,int j) { std::cout << "funcIntInt" << std::endl; } int main(void) { char ch = 7; int i = 77; int j = 777; simpleClass *cls1 = NULL; cls1 = new simpleClass; cls1->func(ch); cls1->func(i); cls1->func(i,j); delete cls1; cls1 = NULL; return 0; }编译运行:
root@se7en-LIFEBOOK-LH531:~/learn/Cpp_Program# g++ reload.cpp -o reload root@se7en-LIFEBOOK-LH531:~/learn/Cpp_Program# ./reload funcChar funcInt funcIntInt可见,函数的重载必须是实参的类型或数量不同.
覆盖:
覆盖是指派生类的某函数和基类完全一致,注意这里是完全一致,而不是像上面的重载一样要有所区别.重载是编译时确定下来的,而覆盖则是在运行时选择的.此时,该方法需要 加关键字"virtual"修饰.至于选择调用是基类的函数还是其派生类的函数的话,由实际的实例对象决定.为了加深印象,下面给出非多态的一个示例:
源码:
#include <iostream> using namespace std; class baseClass { private: unsigned int age; bool sex; public: baseClass(unsigned int a,bool s) { age = a; sex = s; } ~baseClass() { std::cout << "~Base Class"<< std::endl; } unsigned int baseGetAge(void); bool baseGetSex(void); void display(void); }; unsigned int baseClass::baseGetAge(void) { return age; } bool baseClass::baseGetSex(void) { return sex; } void baseClass::display(void) { std::cout << "base Class Display" << std::endl; } class deriveClass:public baseClass { private: unsigned int score,number; public: deriveClass(unsigned int a,bool se,unsigned int sc,unsigned int nu):baseClass(a,se) { score = sc; number = nu; } ~deriveClass() { std::cout << "~derive Class" << std::endl; } unsigned int deriveGetAge(void); bool deriveGetSex(void); unsigned int deriveGetScore(void); unsigned int deriveGetNumber(void); void display(void); }; unsigned int deriveClass::deriveGetAge(void) { return baseGetAge(); } bool deriveClass::deriveGetSex(void) { return baseGetSex(); } unsigned int deriveClass::deriveGetScore(void) { return score; } unsigned int deriveClass::deriveGetNumber(void) { return number; } void deriveClass::display(void) { std::cout << "derive Class Display" << std::endl; } int main(void) { deriveClass *clsDerive = NULL; baseClass *clsBase = NULL; clsDerive = new deriveClass(18,0,100,26); clsBase = clsDerive; std::cout << "Age = " << clsDerive->deriveGetAge()<< std::endl; std::cout << "Sex = " << clsDerive->deriveGetSex()<< std::endl; std::cout << "Score = " << clsDerive->deriveGetScore()<< std::endl; std::cout << "Number = " << clsDerive->deriveGetNumber()<< std::endl; clsBase->display(); clsDerive->display(); delete clsDerive; clsDerive = NULL; return 0; }编译运行:
root@se7en-LIFEBOOK-LH531:~/learn/Cpp_Program# g++ class.cpp -o class root@se7en-LIFEBOOK-LH531:~/learn/Cpp_Program# ./class Age = 18 Sex = 0 Score = 100 Number = 26 base Class Display derive Class Display ~derive Class ~Base Class查看源码,基类及其派生类都有完全一样的函数display().当用基类指针时(见clsBase->display()),调用的是基类的的display();当用派生类指针时(见clsDerive->display()),调用的是派生类的display().这很符合常规的逻辑,什么样的对象,操作该对象的行为.下面在上述的代码里面只多增加了关键字"virtual".如下:
#include <iostream> using namespace std; class baseClass { private: unsigned int age; bool sex; public: baseClass(unsigned int a,bool s) { age = a; sex = s; } ~baseClass() { std::cout << "~Base Class"<< std::endl; } unsigned int baseGetAge(void); bool baseGetSex(void); virtual void display(void); }; unsigned int baseClass::baseGetAge(void) { return age; } bool baseClass::baseGetSex(void) { return sex; } void baseClass::display(void) { std::cout << "base Class Display" << std::endl; } class deriveClass:public baseClass { private: unsigned int score,number; public: deriveClass(unsigned int a,bool se,unsigned int sc,unsigned int nu):baseClass(a,se) { score = sc; number = nu; } ~deriveClass() { std::cout << "~derive Class" << std::endl; } unsigned int deriveGetAge(void); bool deriveGetSex(void); unsigned int deriveGetScore(void); unsigned int deriveGetNumber(void); virtual void display(void); }; unsigned int deriveClass::deriveGetAge(void) { return baseGetAge(); } bool deriveClass::deriveGetSex(void) { return baseGetSex(); } unsigned int deriveClass::deriveGetScore(void) { return score; } unsigned int deriveClass::deriveGetNumber(void) { return number; } void deriveClass::display(void) { std::cout << "derive Class Display" << std::endl; } int main(void) { deriveClass *clsDerive = NULL; baseClass *clsBase = NULL; clsDerive = new deriveClass(18,0,100,26); clsBase = clsDerive; std::cout << "Age = " << clsDerive->deriveGetAge()<< std::endl; std::cout << "Sex = " << clsDerive->deriveGetSex()<< std::endl; std::cout << "Score = " << clsDerive->deriveGetScore()<< std::endl; std::cout << "Number = " << clsDerive->deriveGetNumber()<< std::endl; clsBase->display(); clsDerive->display(); delete clsDerive; clsDerive = NULL; return 0; }编译运行:
root@se7en-LIFEBOOK-LH531:~/learn/Cpp_Program# g++ class.cpp -o class root@se7en-LIFEBOOK-LH531:~/learn/Cpp_Program# ./class Age = 18 Sex = 0 Score = 100 Number = 26 derive Class Display derive Class Display ~derive Class ~Base Class这次两次调用的都是派生类的display()函数.派生类的关键字virtual可以是忽略的不用标识的,但是为了程序的可读性,最好要加上.
至此,我们要调用派生类的方法有两种,派生类对象的静态引用和通过基类指针通过覆盖(虚函数)的方式引用.为了程序的可读性,个人建议选择静态引用.如下:
源码:
#include <iostream> using namespace std; class A { protected: int x; public: A() { x =1000; } virtual void print() { std::cout << "x = " << x << std::endl; }//虚函数 }; class B:public A { private: int y; public: B() { y=2000; } virtual void print() { std::cout << "y = " << y << std::endl; }//派生虚函数 }; class C:public A { private: int z; public: C() { z=3000; } virtual void print() { std::cout << "z = " << z << std::endl; }//派生虚函数 }; int main(void) { A a, *pa; B b; C c; a.print(); b.print(); c.print(); //静态调用 pa=&a; pa->print();//调用类A的虚函数 pa=&b; pa->print();//调用类B的虚函数 pa=&c; pa->print();//调用类C的虚函数 return 0; }编译运行:
root@se7en-LIFEBOOK-LH531:~/learn/Cpp_Program# g++ reference.cpp -o reference root@se7en-LIFEBOOK-LH531:~/learn/Cpp_Program# ./reference x = 1000 y = 2000 z = 3000 x = 1000 y = 2000 z = 3000
纯虚函数:
当我们使用到继承与派生的时候,我们比较关注的并不是基类本身,而是派生类的具体实例,这当然涉及到其中的操作集(函数).多态(覆盖)的实现,可以实现"一个接口,多种功能实现",从而提高程序的可读性和复用性.纯虚函数就是这样的一个"华而不实"的接口标识.定义如下:
在基类中不对虚函数给出有意义的实现,它只是在派生类中有具体的意义.这时基类中的虚函数只是一个入口,具体的目的地由不同的派生类中的对象决定. 这个虚函数称为纯虚函数.其定义形式如下:
class <基类名> { virtual <类型><函数名>(<参数表>)=0; ...... };一个简单的示例代码:
class A{ protected: int x; public: A(){x =1000;} virtual void print()=0; //定义纯虚函数 }; class B:public A{ //派生类 private: int y; public: B(){ y=2000;} void print(){cout <<“y=”<<y<<‘\n’;}//重新定义纯虚函数 }; class C:public A{ //派生类 int z; public: C(){z=3000;} void print(){cout <<“z=”<<z<<‘\n’;}//重新定义纯虚函数 }; void main(void ) { A *pa; B b; C c; pa=&b; pa->print(); pa=&c; pa->print(); A a; pa=&a; pa->print( ); }
可见,重载、覆盖二者的区别为:
选择时机: 重载:编译时决定; 覆盖:运行时决定. 存在形式: 重载:部分相同; 覆盖:完全一致.