1、虚函数
在成员函数前面加virtual后,该函数就称为虚函数,此时该类就会像虚继承一样多了一个虚表指针(虚函数表指针、虚指针)
2、虚函数表
虚表指针指向的是属于该类的一张表格的首地址,该表格中记录了该类的所有虚函数的首地址
如果类中没有其他成员变量
通过((void(*)(void))(*(int*)*(int*)b))(); 可以直接通过虚函数表以及虚表指针来访问虚函数表中第一个虚函数void func(void)
#include <iostream>
using namespace std;
class Base
{
public:
virtual void func(void)
{
cout << "Base func" <<endl;
}
virtual void func1(void)
{
cout << "Base func1" <<endl;
}
};
int main(int argc,const char* argv[])
{
cout << sizeof(Base)<<endl;
Base* b = new Base;
((void(*)(void))(*(int*)*(int*)b))();
}
3、覆盖
当使用virtual来修饰父类的成员函数时,此时父类中就会多一个虚表指针以及一张虚函数表,子类继承父类时,会把父类的虚表指针以及虚函数表一起继承过来,然后编译器回去比较父子类中同名的虚成员函数的格式,如果格式完全相同的虚函数,就会把子类中虚函数表中原来同名父类虚函数的地址改为子类同名函数的地址,此时就称为覆盖
此时使用父类指针或引用指向子类对象时,调用虚函数则会去执行被覆盖后的虚函数表中所指向子类的同名且格式相同的成员函数,不再调用父类的同名虚函数
#include <iostream>
using namespace std;
class Base
{
public:
virtual void func(void)
{
cout << "Base func" <<endl;
}
virtual void func1(void)
{
cout << "Base func1" <<endl;
}
};
class Son:public Base
{
public:
void func(void)
{
cout<< "Son func" <<endl;
}
};
int main(int argc,const char* argv[])
{
cout << sizeof(Base)<<endl;
Base* s = new Son;
s->func();
}
4、构成覆盖的条件
①、子类以public继承父类
②、父类中被覆盖的函数必须是virtual修饰的成员函数
③、子类中必须有与父类虚函数同名的成员函数,且该函数的返回值、参数列表、常属性都必须相同
④、返回值类型相同,或者子类同名成员函数的返回值类型可以向父类虚函数的返回值类型做隐式转换,且有继承关系。
#include <iostream>
using namespace std;
class Base
{
public:
virtual Base* func(void)
{
cout << "Base func" <<endl;
}
virtual void func1(void)
{
cout << "Base func1" <<endl;
}
};
class Son:public Base
{
public:
Son* func(void)
{
cout<< "Son func" <<endl;
}
};
int main(int argc,const char* argv[])
{
cout << sizeof(Base)<<endl;
Base* s = new Son;
s->func();
}
标签:虚表,函数,子类,void,父类,指针
From: https://blog.csdn.net/xjl1849395627/article/details/142526188