继承和多态-虚函数
本来基类指针是指向基类对象的,如果用它指向派生类对象,则自动进行指针类型转化,将派生类的指针转化为基类的指针,这样基类的指针指向派生类对象中基类的部分。
但是虚函数正好解决了这一点,在基类中将display函数申明为虚函数,在声明派生类时被重载,这时派生类的同名函数display取代了基类的虚函数(同名隐藏规则).因此是基类指针指向派生类后,调用display函数是调用了派生类的display函数。
一.虚函数总结:
当把某个成员函数声明为虚函数后,允许在在其派生类中对该函数进行重新定义,赋予新的功能,并且可以通过指向基类的指针指向同一类族的不同类的对象,从而调用其中的同名函数。
二.虚函数的使用方法
(1)在基类中用virtual声明成员函数为基函数,在类外定义虚函数时不必在家virtual;
(2)在派生类中重新定义此函数,函数名、函数类型、函数参数个数和类型必须与基类的虚函数相同,根据派生类的需要重新定义函数体。
当一个成员函数被声明为虚函数后,其派生类中的同名函数都被自动成为虚函数。因此在派生类中重新声明该函数时,可以加virtual也可以不加。但是呢,为了程序结构更加清晰,我觉着还是加了好呢,你们们觉得呢????
(3)定义一个指向基类对象的指针变量,并使他们指向同一类族中需要调用该函数的对象。
(4)通过指针变量调用此虚构函数,此时调用的就是指针变量指向的对象的同名函数。
(5)虚函数的作用就是允许在派生类中对基类的虚函数进行重新定义
上面给大家介绍了那么多,辣么问题来了什么情况下把成员函数声明为基函数呢?
(1)首先看成员函数所在的类是否会作为基类,然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能一般将其声明为虚函数
(2)应考虑对成员函数的调用是通过对像名还是通过指针或引用去访问,如果是通过基类的引用或指针去访问,则应当声明为基函数。
使用虚函数系统会有一定的开销,当一个类带有虚函数时,编译系统会为该类构造一个虚函数表,它是一个指针数组,存放每个虚函数的入口地址,系统在进行动态关联时的时间开销是很少的,因此多态是高效滴。
#include<iostream>
#include<string>
using namespace std;
//声明基类student
class Student
{
public:
Student(int,string,float);
virtual void display();
/*friend ostream& operator<<(ostream& os,Student& s);*/
protected:
int _num;
string _name;
float _score;
};
//student 类成员函数
Student::Student(int num,string name,float score)
:_num(num)
,_name(name)
,_score(score)
{}
void Student::display()
{
cout<<"display1"<<endl;
cout<<_num<<" "<<_name<<" "<<_score<<" "<<endl;
}
/*ostream& operator<<(ostream& os,Student& s)
{
os<<s._num<<" "<<s._name<<" "<<s._score<<endl;
}*/
//声明公用派生类
class Graduate:public Student
{
public:
Graduate(int,string,float,float);
virtual void display();
/*friend ostream& operator<<(ostream& os,Student& g);*/
private:
float _wage;
};
//Graduate类成员函数的实现
Graduate::Graduate(int num,string name,float score,float wage)
:Student(num,name,score)
,_wage(wage)
{}
void Graduate::display()
{
cout<<"display2"<<endl;
cout<<_num<<" "<<_name<<" "<<_score<<" "<<_wage<<endl;
}
int main()
{
Student student1(1001,"lili",88.8);
Graduate graduate1(1002,"huhu",99.9,1220);
Student *ps=&student1;//指向基类对象的指针变量,
ps->display();
ps=&graduate1;//指向基类的指针变量访问子类数据成员
ps->display();
system("pause");
return 0;
}
原文:http://10808695.blog.51cto.com/10798695/1752873