类似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( );
}
可见,重载、覆盖二者的区别为:
选择时机:
重载:编译时决定;
覆盖:运行时决定.
存在形式:
重载:部分相同;
覆盖:完全一致.