首先虚函数是为了实现多态的,统一接口。其中我就虚函数的性质做一些讲解,希望能够帮助大家。
在内存中地址是整型,可以将类的地址转化成一个2维指针,在通过该地址 寻找虚函数地址。函数出现((Fun)*(*pVta+1))();就不足以为怪了。
在看看具体的代码吧!
#include"iostream.h"
#include"string.h"
class XS
{
public:
virtual void dispXM()=0; // 纯虚函数,区别就是抽象的,不需要给出具体代码,只要给出接口就行
virtual void dispXB()=0;
virtual void dispNL()=0;
};
class CZS:public XS // 继承XS类 并实现函数接口,说明该类不是抽象类
{
public:
CZS(char * m="张三",int b=1,int n=14);
void dispXM();
void dispXB();
void dispNL();
protected:
char xm[9];
int xb,nl;
};
CZS::CZS(char*m,int b,int n)
{
strcpy(xm,m);
xb = b;
nl = n;
}
void CZS::dispXM()
{
cout<<"姓名:"<<xm<<endl;
}
void CZS::dispXB()
{
if(1 == xb)
{
cout<<"性别:男"<<endl;
}
else
{
cout<<"性别:女"<<endl;
}
}
void CZS::dispNL()
{
if(nl > 0)
{
cout<<"年龄:"<<nl<<endl;
}
else
{
cout<<"不合法"<<endl;
}
}
class GZS:public XS{
public:
GZS(char * m="张三",int b=1,int n=17);
void dispXM();
void dispXB();
void dispNL();
protected:
char xm[9];
int xb,nl;
};
GZS::GZS(char*m,int b,int n)
{
strcpy(xm,m);
xb = b;
nl = n;
}
void GZS::dispXM()
{
cout<<"姓名:"<<xm<<endl;
}
void GZS::dispXB()
{
if(1 == xb)
{
cout<<"性别:男"<<endl;
}
else
{
cout<<"性别:女"<<endl;
}
}
void GZS::dispNL()
{
if(nl > 0)
{
cout<<"年龄:"<<nl<<endl;
}
else
{
cout<<"不合法"<<endl;
}
}
class DXS:public XS{
public:
DXS(char * m="张三",int b=1,int n=20);
void dispXM();
void dispXB();
void dispNL();
protected:
char xm[9];
int xb,nl;
};
DXS::DXS(char*m,int b,int n)
{
strcpy(xm,m);
xb = b;
nl = n;
}
void DXS::dispXM()
{
cout<<"姓名:"<<xm<<endl;
}
void DXS::dispXB()
{
if(1 == xb)
{
cout<<"性别:男"<<endl;
}
else
{
cout<<"性别:女"<<endl;
}
}
void DXS::dispNL()
{
if(nl > 0)
{
cout<<"年龄:"<<nl<<endl;
}
else
{
cout<<"不合法"<<endl;
}
}
void displayP(XS *xs) // 实现多态性,通过传得对象,输出对应对象的参数
{
xs->dispXM();
xs->dispXB();
xs->dispNL();
}
void displayR(XS &xs) // 通过对象的引用
{
xs.dispXM();
xs.dispXB();
xs.dispNL();
}
typedef void (*Fun)(void); // 函数的指针定义,函数的指针的指针
void main()
{
CZS czs("赵一",1,12);
GZS gzs("钱二",0,15);
DXS dxs("孙三",1,18);
XS *p;//定义抽象基类的指针变量p
p=&czs;//将初中生对象czs的地址赋给p
displayP(p);
p=&gzs;//将高中生对象czs的地址赋给p
displayP(p);
p=&dxs;//将大学生对象czs的地址赋给p
displayP(p);
cout<<"\n----------------------------------------\n";
XS &r1=czs;//定义抽象基类的引用变量r1为czs的别名
displayR(r1);
XS &r2=gzs;//定义抽象基类的引用变量r2为czs的别名
displayR(r2);
XS &r3=dxs;//定义抽象基类的引用变量r3为czs的别名
displayR(r3);
cout<<"\n----------------------------------------\n";
int** pVta = (int**)&dxs;
((Fun)*(*pVta+1))(); // 指定虚函数
}
编译器会为虚函数维护一个虚函数表,可以通过类的地址,轻松的找到虚函数的入口地址。通过指针的形式或数组的形式((Fun)*(*pVta+1))();
讲讲关于多态的实现,我们发现通过基类的指针对象,当子类对象的地址赋给该指针对象,由于虚函数,该指针就指向了自己类的函数,这样的向上映射,就实现了函数的多态
也就是函数体只需要给出基类对象的指针对象,就可以对子类进行相关操作。函数段为:
void displayP(XS *xs) // 实现多态性,通过传得对象,输出对应对象的参数
{
xs->dispXM();
xs->dispXB();
xs->dispNL();
}
但注意,不是虚函数,编译器不会安排函数表的,如果对非虚函数类进行
((Fun)*(*pVta+1))(); 虽然编译的时候不报错,但运行的时候肯定报错,原因是找不到这个函数的入口地址。
关于虚函数的理解就讲到这里了。。。希望大家多多交流指正。。。。
留住最真的于2012.11.09 0:30写~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~