1、虚函数
简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。C++中虚函数的作用主要是实现多态机制。所谓多态就是用父类指针指向子类对象,然后通过父类指针调用实际子类的成员函数,这种技术可以让父类指针有“多种形态”。
2、纯虚函数
在虚函数形参后面写上=0,则该函数为纯虚函数。纯虚函数没有函数体;纯虚函数只有函数的名字而不具备函数的功能,不能被调用。纯虚函数的作用是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对他进行定义。如果在一个类中声明了纯虚函数,在其派生类中没有对其函数进行定义,则该虚函数在派生类中仍然为纯虚函数。
3、虚函数表
虚函数是通过虚函数表来实现的,在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆盖的问题。在有虚函数的实例中这张表被分配在这个实例的内存中,所以当我们用父类指针来操作一个子类的时候,这张虚函数表就像地图一样指明实际所应该调用的函数。
eg:
class Base{
public:
virtual void f(){cout<<"Base::f"<<endl;}
virtual void g(){cout<<"Base::g"<<endl;}
virtual void h(){cout<<"Base::h"<<endl;}
};
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout<<"虚函数表的地址:"<<(int*)(&b)<<endl;
cout<<"虚函数表的第一个函数地址:"<<(int*)*(int*)(&b)<<endl;
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
/*
实际运行经果如下:(Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)
虚函数表地址:0012FED4
虚函数表的第一个函数地址:0044F148
Base::f
同理可得到其他虚函数:
(Fun)*((int*)*(int*)(&b)+0); // Base::f()
(Fun)*((int*)*(int*)(&b)+1); // Base::g()
(Fun)*((int*)*(int*)(&b)+2); // Base::h()
*/
(1)一般继承:假如有派生类继承基类,但是没有覆盖其虚函数
class Derive :public Base
{
public:
virtual void f1(){cout<<"Derive::f1"<<endl;}
virtual void g1(){cout<<"Derive::g1"<<endl;}
virtual void h1(){cout<<"Derive::h1"<<endl;}
};
Derive d;
((Fun)*((int*)*(int*)(&d)+0))(); // Base::f()
((Fun)*((int*)*(int*)(&d)+1))(); // Base::g()
((Fun)*((int*)*(int*)(&d)+2))(); // Base::h()
((Fun)*((int*)*(int*)(&d)+3))(); // Derive::f1()
((Fun)*((int*)*(int*)(&d)+4))(); // Derive::g1()
((Fun)*((int*)*(int*)(&d)+5))(); // Derive::h1()
// 父类指针指向子类对象
Base* b = &d;
((Fun)*((int*)*(int*)b+0))(); // Base::f()
((Fun)*((int*)*(int*)b+1))(); // Base::g()
((Fun)*((int*)*(int*)b+2))(); // Base::h()
((Fun)*((int*)*(int*)b+3))(); // Derive::f1()
((Fun)*((int*)*(int*)b+4))(); // Derive::g1()
((Fun)*((int*)*(int*)b+5))(); // Derive::h1()
/*
1、虚函数按照其声明顺序放在
2、父类的虚函数在子类的虚函数前面
*/
(2)一般继承:假如派生类覆盖了父类的虚函数
class Derive :public Base
{
public:
virtual void f(){cout<<"Derive::f"<<endl;}
virtual void g1(){cout<<"Derive::g1"<<endl;}
virtual void h1(){cout<<"Derive::h1"<<endl;}
}
Derive b;
Base* d = &b;
(Fun)*((int*)*(int*)d+0); // Derive::f()
(Fun)*((int*)*(int*)d+1); // Base::g()
(Fun)*((int*)*(int*)d+2); // Base::h()
(Fun)*((int*)*(int*)d+3); // Derive::g1()
(Fun)*((int*)*(int*)d+4); // Derive::h1()
// 由上可知,被覆盖的取代原来父类虚函数的位置,没覆盖的按声明顺序
(3)多重继承:无虚函数覆盖
class Base1{
public:
virtual void f(){cout<<"Base1::f"<<endl;}
virtual void g(){cout<<"Base1::g"<<endl;}
virtual void h(){cout<<"Base1::h"<<endl;}
};
class Base2{
public:
virtual void f(){cout<<"Base2::f"<<endl;}
virtual void g(){cout<<"Base2::g"<<endl;}
virtual void h(){cout<<"Base2::h"<<endl;}
};
class Base3{
public:
virtual void f(){cout<<"Base3::f"<<endl;}
virtual void g(){cout<<"Base3::g"<<endl;}
virtual void h(){cout<<"Base3::h"<<endl;}
};
class Derive1: public Base1,public Base2,public Base3
{
public:
virtual void f1(){cout<<"Derive1::f1"<<endl;}
virtual void g1(){cout<<"Derive1::g1"<<endl;}
};
// #1 直接从子类对象查找虚函数对应的地址
Derive1 d;
((Fun)*((int*)*((int*)(&d)+0)+0))(); // Base1::f
((Fun)*((int*)*((int*)(&d)+0)+1))(); // Base1::g
((Fun)*((int*)*((int*)(&d)+0)+2))(); // Base1::h
((Fun)*((int*)*((int*)(&d)+0)+3))(); // Derive1::f1
((Fun)*((int*)*((int*)(&d)+0)+4))(); // Derive1::g1
((Fun)((int*)*((int*)(&d)+1)+0))(); // Base2::f
((Fun)*((int*)*((int*)(&d)+1)+1))(); // Base2::g
((Fun)*((int*)*((int*)(&d)+1)+2))(); // Base2::h
((Fun)*((int*)*((int*)(&d)+2)+0))(); // Base3::f
((Fun)*((int*)*((int*)(&d)+2)+1))(); // Base3::f
((Fun)*((int*)*((int*)(&d)+2)+2))(); // Base3::f
// #2 从父类指针指向子类对象查找虚函数对应的地址
Base1* b1 = &d;
((Fun)*((int*)*((int*)b1+0)+0))(); // Base1::f
((Fun)*((int*)*((int*)b1+0)+1))(); // Base1::g
((Fun)*((int*)*((int*)b1+0)+2))(); // Base1::h
((Fun)*((int*)*((int*)b1+0)+3))(); // Derive1::f1
((Fun)*((int*)*((int*)b1+0)+4))(); // Derive1::g1
Base2* b2 = &d;
((Fun)*((int*)*((int*)b2+0)+0))(); // Base2::f
((Fun)*((int*)*((int*)b2+0)+1))(); // Base2::g
((Fun)*((int*)*((int*)b2+0)+2))(); // Base2::h
Base3* b3 = &d;
((Fun)*((int*)*((int*)b3+0)+0))(); // Base3::f
((Fun)*((int*)*((int*)b3+0)+1))(); // Base3::g
((Fun)*((int*)*((int*)b3+0)+2))(); // Base3::h
/*
#1和#2都说明了子类的虚函数是紧接着第一个继承的父类,
而且多重继承的虚函数表是不一样的,
(1)对于子类对象来说,虚函数表像一个二维数组一样,
数组的第一行放置第一个继承父类的虚函数和子类本身的虚函数
数组的第二行放置第二个继承父类的虚函数
数组的第三行放置第个继承父类的虚函数
(2)对于父类来说,
Base1的虚函数表有其自身的虚函数以及子类的虚函数
Base2和Base3的虚函数表都只有其自身的虚函数
*/
(4)多重继承:有虚函数覆盖
class Derive2: public Base1,public Base2,public Base3
{
public:
virtual void f(){cout<<"Derive2::f"<<endl;}
virtual void g1(){cout<<"Derive2::g1"<<endl;}
};
// #1 直接从子类对象查找虚函数对应的地址
Derive2 d;
((Fun)*((int*)*((int*)(&d)+0)+0))(); // Derive2::f
// #2 从父类指针指向子类对象查找虚函数对应的地址
Base1* b1 = &d;
((Fun)*((int*)*((int*)b1+0)+0))(); // Derive2::f
Base2* b2 = &d;
((Fun)*((int*)*((int*)b2+0)+0))(); // Derive2::f
Base3* b3 = &d;
((Fun)*((int*)*((int*)b3+0)+0))(); // Derive2::f
// 这时候每个父类的f()虚函数都会被子类的f()所覆盖,其他虚函数不变
另外,需要注意的是,当父类指针指向子类对象时,不能访问子类特有的虚函数,只能访问子类覆盖父类的虚函数。