说说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))(); 虽然编译的时候不报错,但运行的时候肯定报错,原因是找不到这个函数的入口地址。
相关文章
- Visual C++中最常用的类与API函数 2012/11/13
- 说说C++下深拷贝和浅拷贝 2012/11/12
- C/C++数组名与指针区别 2012/11/12
- C++拷贝构造函数和赋值构造函数 2012/11/12
- 预处理指令#pragma详细解释 2012/11/12
- 如何自己编写Makefile 2012/11/12
- Google C++编程风格指南(八):规则之例外 2012/11/09
- Google C++编程风格指南(七):格式 2012/11/09
- Google C++编程风格指南(六):代码注释 2012/11/09
- Google C++编程风格指南(五):命名约定 2012/11/09