说说C++虚函数


C++ #虚函数2012-11-13 10:38

首先虚函数是为了实现多态的,统一接口。其中我就虚函数的性质做一些讲解,希望能够帮助大家。

在类的继承中有时为了统一接口,

在内存中地址是整型,可以将类的地址转化成一个2维指针,在通过该地址 寻找虚函数地址。函数出现((Fun)*(*pVta+1))();就不足以为怪了。

在看看具体的代码吧!

#include"iostream.h"
#include"string.h"

class XS
{
public:
 virtual void dispXM()=0;   // 纯虚函数,区别就是抽象的,不需要给出具体代码,只要给出接口就行 http://yige.org/cpp/
 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 <<"----------------------------------------";


    XS &r1=czs;//定义抽象基类的引用变量r1为czs的别名
   displayR(r1);


    XS &r2=gzs;//定义抽象基类的引用变量r2为czs的别名
   displayR(r2);


   XS &r3=dxs;//定义抽象基类的引用变量r3为czs的别名
   displayR(r3); 
   cout <<"----------------------------------------";

   int** pVta = (int**)&dxs;

    ((Fun)*(*pVta+1))();  // 指定虚函数
}

 

现在讲讲类中的具体有什么东东,

编译器会为虚函数维护一个虚函数表,可以通过类的地址,轻松的找到虚函数的入口地址。通过指针的形式或数组的形式((Fun)*(*pVta+1))(); 

 

讲讲关于多态的实现,我们发现通过基类的指针对象,当子类对象的地址赋给该指针对象,由于虚函数,该指针就指向了自己类的函数,这样的向上映射,就实现了函数的多态

也就是函数体只需要给出基类对象的指针对象,就可以对子类进行相关操作。函数段为:

void displayP(XS *xs)   // 实现多态性,通过传得对象,输出对应对象的参数
{
 xs- >dispXM();
 xs- >dispXB();
 xs- >dispNL();
}

在给出CZS类的函数覆盖的图片

但注意,不是虚函数,编译器不会安排函数表的,如果对非虚函数类进行

((Fun)*(*pVta+1))();  虽然编译的时候不报错,但运行的时候肯定报错,原因是找不到这个函数的入口地址。


相关文章

粤ICP备11097351号-1