一、虚函数:加virtual关键词的函数
- 虚函数作用:C++中的多态,进行动态绑定(父类指针可指向子类的对象),直到运行时才知道要具体调用哪个版本(哪个类定义)的函数;
- 它是通过虚表实现的,简单理解如下:
代码分析:
#include<iostream>
using namespace std;
class Base
{
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
int main()
{
Base b;
cout<<"b 对象的大小是: "<<sizeof(b)<<endl;
cout<<"b 对象的起始地址是:"<<&b<<endl;
cout<<"虚函数表地址: "<<*(int *)(&b)<<endl;
cout<< "虚函数表 — 第一个函数地址:" << *((int*)*(int*)(&b)) << endl;
cout << "虚函数表 — 第二个函数地址:" << *((int*)*(int*)(&b)+1) << endl;
cout << "虚函数表 — 第三个函数地址:" << *((int*)*(int*)(&b)+2) << endl;
cout<<"**********************************************************************"<<endl;
Base c;
cout<<"c 对象的起始地址是:"<<&c<<endl;
cout<<"虚函数表地址: "<<*(int *)(&c)<<endl;
cout<< "虚函数表 — 第一个函数地址:" << *((int*)*(int*)(&c)) << endl;
cout << "虚函数表 — 第二个函数地址:" << *((int*)*(int*)(&c)+1) << endl;
cout << "虚函数表 — 第三个函数地址:" << *((int*)*(int*)(&c)+2) << endl;
//(int *)&b ->把b的地址转成(int *),*(int *)&b即基表指针,
//(int*)*(int*)(&b)->基表指针指向的函数地址,*((int*)*(int*)(&b))所指向的函数内容
return 0;
}
结果截屏:
总结:虚表是属于类的,它只有一份,对象在被实例化的时候,首先前四个字节存储虚表指针,即类的虚表地址。
二、用虚函数实现多态。
代码:
class Base
{
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
class Derive:public Base
{
public:
void f(){ cout << "Derive::f" <<endl; }
virtual void g(){ cout << "Derive::g" <<endl; }
virtual void h1(){ cout << "Derive::h1" <<endl; }
};
int main()
{
typedef void(*Fun)(void);
Derive d;
Fun pFun = NULL;
pFun = (Fun)*((int*)*(int*)(&d));
pFun();
pFun = (Fun)*((int*)*(int*)(&d)+1);
pFun();
pFun = (Fun)*((int*)*(int*)(&d)+2);
pFun();
pFun = (Fun)*((int*)*(int*)(&d)+3);
pFun();
Base *b = &d;
b->f();
return 0;
}
结果截屏:
总结:1、一旦父类的成员函数声明virtual,其子类的函数不管有没有声明为virtual,都是虚函数;
2、虚表顺序:先基类后派生类,如果派生类有同名的函数,则取代虚表中基类的函数位置;
3、基类指针指向派生类对象,如果调用的函数是虚函数,则调动的是派生类的方法。
三、纯虚函数
class Base//抽象类
{
public :
virtual void fun () = 0; //纯虚函数
};
class Drive:public Base
{
public:
void fun()
{
cout<<"fun"<<endl;
}
};
int main()
{
//Base b; 抽象类不能被实例化
Drive d;
Base *c = &d;
c->fun ();
return 0;
}