关于多态:
从系统的角度看,多态分为静态多态和动态多态。
静态多态是利用重载实现的,在程序编译时确定要调用的是哪个函数,因此静态多态又称为编译时多态。动态多态和虚函数主要研究的是:当一个基类被继承为不同的派生类时,各派生类可以使用与基类成员相同的成员名,如果在运行时用同一个成员名调用类对象的成员,那么会调用哪一个对象的成员?
也就是,通过继承而产生了相关的不同派生类,与基类成员同名的成员在不同的派生类中有不同的含义。即“一个接口,多个方法”。
关于虚函数:
在同一个类中是不能定义两个名字相同、参数个数和类型完全相同的函数,否则就是重复定义。但是在类的继承层次结构中,在不同的层次中可以出现名字相同、参数个数和类型相同而功能不同的函数(这是因为类域的原因,即他们在不同的作用域内)。这时系统会根据同名覆盖的原则决定调用的对象。
class Student
{
public:
void display()
{
cout << _age << endl;
}
protected:
int _age;
};
class Student1 :public Student
{
public:
void display()
{
cout << _name << "--" << _age << endl;
}
protected:
char _name;
};
★虚函数的使用方法:
1、在基类中用virtual声明成员函数是虚函数。(在类外定义时不需要再加virtual)
2、在派生类中重新定义虚函数,要求函数名,函数类型,参数个数和类型完全与基类中的虚函数相同,根据自己的需求定义函数体。C++中规定,当一个成员函数被声明为虚函数后,在派生类中的同名函数都是虚函数。如果在派生类中没有对虚函数重新定义,则派生类简单的继承基类的虚函数。
3、定义一个指向基类对象的指针变量,并使他指向同一类族中需要调用该函数的对象。通过该指针变量调用此虚函数,就相当于指针变量所指向的对象的同名函数。
4、函数重载处理的是同一层次上的同名函数问题,因此是横向重载。虚函数处理的是类的派生层次上的同名函数问题,属于纵向重载。与重载不同的是,虚函数要求函数的首部完全相同。
5、函数重载和通过对象名调用的虚函数,在编译期间即可确定调用的虚函数属于哪一个类,其过程称为静态关联。在运行阶段,基类变量先指向某一个类对象,然后通过此指针变量调用该对象中的函数,这种过程称为动态关联。
★什么时候使用虚函数
1、因为虚函数是用于类的继承层次结构中的,所以只能将类的成员函数声明为虚函数,而不能将普通函数声明为虚函数。
2、一个成员函数被声明为虚函数后,就不能再同一类族中再定义一个非virtual的但是与虚函数首部相同的函数了。
3、如果一个类作为基类,它的成员函数可能会在派生类中发生改变,则应声明为虚函数。
4、如果是通过指向基类对象的指针调用派生类中成员函数,则应声明为虚函数。
5、使用虚函数,系统会有一定的空间开销。当一个类中有虚函数时,编译系统会为该类构造一个虚函数表,它是一个指针数组,用来存放每个虚函数的入口地址。但是系统在进行动态关联时的时间开销很少,所以多态很高效。
6、一般将析构函数声明为虚析构函数,即时基类不需要析构函数,也要显示的定义一个函数体为空放入虚析构函数,以保证在撤销对象动态分配空间时能得到正确的处理。
纯虚函数:
有时在类中将某一成员声明为虚函数,并不是因为基类本身的要求,而是因为派生类的需求,在基类中预留一个函数名,具体功能留给派生类区定义。这种情况下就可以将这个纯虚函数声明为纯虚函数。其一般形式是:
virtual 函数类型 函数名 (参数列表) =0;纯虚函数没有函数体。最后的“=0”只是一种形式,告诉编译系统,它是一个纯虚函数,留在派生类中定义,并没有实际意义。纯虚函数只有在派生类中定义了之后才能被调用。如果在一个类中声明了纯虚函数,而在派生类中没有对该函数定义,则该虚函数在派生类中仍然为纯虚函数。
抽象类:
含有纯虚函数的类就成为抽象类。抽象类只是一种基本的数据类型,用户需要在这个基础上根据自己的需要定义处各种功能的派生类。抽象类的作用就是为一个类族提供一个公共接口。抽象类不能定义对象,但是可以定义指向抽象类的指针变量,通过这个指针变量可以实现多态。