一、虚函数的定义
有关键字virtual修饰的成员函数,为了实现多态。
二、虚函数表
1.虚函数表用来存放虚函数的地址,也称虚表。
2.一个含有虚函数的类中至少有一个虚表。
3.虚表指针:二级指针,虚函数指针的指针,存放在对象模型头部,32位系统中占4个字节,在64位系统中占8个字节。虚表指针中存放着虚表的首地址。可以通过对象实例化的地址得到虚函数表的地址。
4.虚表与虚表指针的关系如下:
三、子类中的虚表
1.单继承无虚函数覆盖:
class Base
{
public:
virtual void Func1()
{
cout << "Base::Func1" << endl;
}
virtual void Func2()
{
cout << "Base::Func2" << endl;
}
};
class Derive :public Base
{
public:
virtual void Func3()
{
cout << "Derive::Func3" << endl;
}
virtual void Func4()
{
cout << "Derive::Func4" << endl;
}
};
typedef void(*VFPTR)();
//打印虚函数表
void PrintVF(VFPTR* VFaddress)
{
cout << "虚表地址:" << VFaddress << endl;
int i = 1;
VFPTR vfunc = VFaddress[0];
while (vfunc != nullptr)
{
cout << "第" << i << "个虚函数地址:" << vfunc << endl;
vfunc();
VFaddress++;
vfunc = *VFaddress;
i++;
}
}
int main()
{
Base b;
Derive d;
cout << "父类虚表:" << endl;
PrintVF((VFPTR*)*(int*)&b);
cout << "子类虚表:" << endl;
PrintVF((VFPTR*)*(int*)&d);
system("pause");
return 0;
}
单继承时,子类中只有一个虚函数表,父类虚函数在前,子类虚函数在后,按照声明顺序存放。
2.单继承有虚函数覆盖
class Base
{
public:
virtual void Func1()
{
cout << "Base::Func1" << endl;
}
virtual void Func2()
{
cout << "Base::Func2" << endl;
}
};
class Derive :public Base
{
public:
virtual void Func1()
{
cout << "Derive::Func1" << endl;
}
virtual void Func2()
{
cout << "Derive::Func2" << endl;
}
virtual void Func3()
{
cout << "Derive::Func3" << endl;
}
virtual void Func4()
{
cout << "Derive::Func4" << endl;
}
};
void PrintVF(VFPTR* VFaddress)
{
cout << "虚表地址:" << VFaddress << endl;
int i = 1;
VFPTR vfunc = VFaddress[0];
while (vfunc != nullptr)
{
cout << "第" << i << "个虚函数地址:" << vfunc << endl;
vfunc();
VFaddress++;
vfunc = *VFaddress;
i++;
}
}
int main()
{
Base b;
Derive d;
cout << "父类虚表:" << endl;
PrintVF((VFPTR*)*(int*)&b);
cout << "子类虚表:" << endl;
PrintVF((VFPTR*)*(int*)&d);
system("pause");
return 0;
}
子类中有一个虚函数表,覆盖的虚函数放在虚函数表中继承于父类的位置,新增的虚函数放在继承的父类虚表的后面。
3.多继承没有虚函数重写:
class Base1
{
public:
virtual void Func1()
{
cout << "Base1::Func1" << endl;
}
virtual void Func2()
{
cout << "Base1::Func2" << endl;
}
};
class Base2
{
public:
virtual void Func1()
{
cout << "Base2::Func1" << endl;
}
virtual void Func2()
{
cout << "Base2::Func2" << endl;
}
};
class Derive :public Base1, Base2
{
public:
virtual void Func3()
{
cout << "Derive::Func3" << endl;
}
virtual void Func4()
{
cout << "Derive::Func4" << endl;
}
};
typedef void(*VFPTR)();
void PrintVF(VFPTR* VFaddress)
{
cout << "虚表地址:" << VFaddress << endl;
int i = 1;
VFPTR vfunc = VFaddress[0];
while (vfunc != nullptr)
{
cout << "第" << i << "个虚函数地址:" << vfunc << endl;
vfunc();
VFaddress++;
vfunc = *VFaddress;
i++;
}
}
int main()
{
Base1 b1;
Base2 b2;
Derive d;
cout << "父类虚表(Base1):" << endl;
PrintVF((VFPTR*)*(int*)&b1);
cout << "父类虚表(Base2):" << endl;
PrintVF((VFPTR*)*(int*)&b2);
cout << "Derive ::Base1:" << endl;
PrintVF((VFPTR*)*(int*)&d);
cout << "Derive ::Base2:" << endl;
PrintVF((VFPTR*)(*(int*)((char*)&d + sizeof(Base1))));
system("pause");
return 0;
}
多继承时,子类中虚表个数等于直接父类的个数,子类中新增的虚函数放在第一个直接父类的虚表末尾,按照声明顺序存放。
4.多继承有虚函数重写时
class Base1
{
public:
virtual void Func1()
{
cout << "Base1::Func1" << endl;
}
virtual void Func2()
{
cout << "Base1::Func2" << endl;
}
};
class Base2
{
public:
virtual void Func1()
{
cout << "Base2::Func1" << endl;
}
virtual void Func2()
{
cout << "Base2::Func2" << endl;
}
};
class Derive :public Base1, Base2
{
public:
virtual void Func1()
{
cout << "Derive::Func1" << endl;
}
virtual void Func3()
{
cout << "Derive::Func3" << endl;
}
virtual void Func4()
{
cout << "Derive::Func4" << endl;
}
};
typedef void(*VFPTR)();
void PrintVF(VFPTR* VFaddress)
{
cout << "虚表地址:" << VFaddress << endl;
int i = 1;
VFPTR vfunc = VFaddress[0];
while (vfunc != nullptr)
{
cout << "第" << i << "个虚函数地址:" << vfunc << endl;
vfunc();
VFaddress++;
vfunc = *VFaddress;
i++;
}
}
int main()
{
Base1 b1;
Base2 b2;
Derive d;
cout << "父类虚表(Base1):" << endl;
PrintVF((VFPTR*)*(int*)&b1);
cout << "父类虚表(Base2):" << endl;
PrintVF((VFPTR*)*(int*)&b2);
cout << "Derive ::Base1:" << endl;
PrintVF((VFPTR*)*(int*)&d);
cout << "Derive ::Base2:" << endl;
PrintVF((VFPTR*)(*(int*)((char*)&d + sizeof(Base1))));
system("pause");
return 0;
}
多继承有虚函数重写时,子类中虚表个数等于直接父类的个数,子类中重写的虚函数覆盖继承的父类的虚函数,子类中新增的虚函数放在第一个直接父类的虚表末尾,按照声明顺序存放。