上一次我们说到了静态结合,定义指向基类的指针,当把基类对象和派生类对象的基址赋给指针后,通过指针调用disp函数,我们会发现:调用的成员函数都为基类的disp函数。 这是因为我们在一开始就定义指针指向基类,在运行的过程中无法改变这种结合,所以叫做静态结合。
如果当我们把基类对象和派生类对象的基址赋给指针后,通过指针调用disp函数,能够分别实现基类和派生类成员函数disp的调用。也就是实现了所谓的动态结合。 若要实现动态结合,我们需要使用虚函数。
/*说明虚函数的定义和使用*/
#include<iostream>
using namespace std;
class test1
{
int x;
int y;
public:
test1():x(0),y(0)
{
}
test1(int a,int b):x(a),y(b)
{
}
virtual void disp()
{
cout<<"x="<<x<<endl;
cout<<"y="<<y<<endl;
}
};
class test2:public test1
{
int z;
public:
test2():test1()
{
z=0;
}
test2(int a,int b,int c):test1(a,b)
{
z=c;
}
void disp()
{
test1::disp();
cout<<"z="<<z<<endl;
}
};
int main()
{
test1 p(1,2),*r;
test2 q(10,20,30);
cout<<"===p"<<endl;
p.disp();
cout<<"===q"<<endl;
q.disp();
cout<<"===*r->p"<<endl;
r=&p;
r->disp();
cout<<"===*r->q"<<endl;
r=&q;
r->disp();
}
说明:
(1)虚函数的定义是在基类的成员函数前面加上virtual
关键字。
(2)要利用指针实现程序的多样性,必须注意,指针必须定义为指向基类的指针。
- 如果利用指针调用的函数只在基类中存在,直接调用基类中的函数。
- 如果利用指针调用的函数只在派生类中存在,编译错误。
- 如果利用指针调用的函数在基类、派生类中都存在,但不是
virtual
函数,调用基类中的函数。 - 如果利用指针调用的函数在基类、派生类中都存在,且是
virtual
函数,调用派生中的函数。
(3)判断虚函数的准则
- 与基类的虚函数有相同的函数名。
- 与基类的虚函数有相同的参数个数及其类型。
- 与基类的虚函数有相同的返回值类型。
/*利用指针、引用和对象名来调用虚函数*/
#include<iostream>
using namespace std;
class test1
{
int x;
int y;
public:
test1(int a,int b):x(a),y(b)
{
}
virtual void disp()
{
cout<<"x="<<x<<" "<<"y="<<y<<endl;
}
};
class test2:public test1
{
int z;
public:
test2(int a,int b,int c):test1(a,b)
{
z=c;
}
void disp()
{
test1::disp();
cout<<"z="<<z<<endl;
}
};
int main()
{
test2 s(1,2,3);
cout<<"指针:"<<endl;
test1 *p=&s;
p->disp();
cout<<"引用:"<<endl;
test1 &q=s;
q.disp();
cout<<"对象:"<<endl;
test1 r=s;
r.disp();
}
由结果可以看出,将派生类对象的地址赋给指向基类的指针或基类对象的引用,通过调用虚函数可以实现多态。但将派生类对象赋给基类对象的方式,并不能实现多态。