class TestObject
{
public:
TestObject()
{
}
virtual void Test()
{
}
};
class TestObject1
{
public:
TestObject1()
{
}
void Test()
{
}
};
int main()
{
TestObject Object;
TestObject1 Object1;
std::cout << sizeof(Object) << std::endl;
std::cout << sizeof(Object1) << std::endl;
}
X86平台虚指针 4个字节
X64平台虚指针 8个字节
1.为什么会有虚指针呢?
虚函数指针 (virtual function pointer) 从本质上来说就只是一个指向函数的指针,与普通的指针并无区别。它指向用户所定义的虚函数,具体是在子类里的实现,当子类调用虚函数的时候,实际上是通过调用该虚函数指针从而找到接口。
虚函数指针是确实存在的数据类型,在一个被实例化的对象中,它总是被存放在该对象的地址首位,这种做法的目的是为了保证运行的快速性。与对象的成员不同,虚函数指针对外部是完全不可见的,除非通过直接访问地址的做法或者在DEBUG模式中,否则它是不可见的也不能被外界调用。
只有拥有虚函数的类才会拥有虚函数指针,每一个虚函数也都会对应一个虚函数指针。所以拥有虚函数的类的所有对象都会因为虚函数产生额外的开销,并且也会在一定程度上降低程序速度。与JAVA不同,C++将是否使用虚函数这一权利交给了开发者,所以开发者应该谨慎的使用。
2.为什么调用普通函数比调用虚函数的效率高?
因为普通函数是静态联编的,而调用虚函数是动态联编的。
联编的作用:程序调用函数,编译器决定使用哪个可执行代码块。(所谓联编就是将函数名和函数体的程序连接到一起的过程)
静态联编 :在编译的时候就确定了函数的地址,然后call就调用了。
(静态联编本质是系统用实参与形参进行匹配,对于重名的重载函数根据参数上的差异进行区分,然后进行联编,从而实现编译时的多态。函数的选择基于指向对象的指针类型或者引用类型。)
动态联编 : 首先需要取到对象的首地址,然后再解引用取到虚函数表的首地址后,再加上偏移量才能找到要调的虚函数,然后call调用。
(动态联编本质上是运行阶段执行的联编,当程序调用某一个函数时,系统会根据当前的对象类型去寻找和连接其程序的代码。函数的选择基于对象的类型。
3.为什么要用虚函数表(存函数指针的数组)?
同一个类的多个对象的虚函数表是同一个,所以这样就可以节省空间,一个类自己的虚函数和继承的虚函数还有重写父类的虚函数都会存在自己的虚函数表。同时,虚函数表本质是一个地图导航,可以清楚告诉一个想要操作子类的父类指针到底该使用哪个函数
虚函数表详解
class TestObject
{
public:
int x;
TestObject()
{
}
virtual void Test()
{
}
};
class TestObject1
{
public:
int x;
TestObject1()
{
}
void Test()
{
}
};
int main()
{
TestObject1* Object1 = new TestObject1();
std::cout << Object1 << std::endl;
std::cout << &Object1->x << std::endl;
std::cout << sizeof(Object1) << std::endl;
std::cout << "-----------------下面是虚函数----------------------------------" << std::endl;
TestObject* Object = new TestObject();
std::cout << Object << std::endl;
std::cout << &Object->x << std::endl;
std::cout << sizeof(Object) << std::endl;
}
从上面代码可以看出虚函数表存在了对象实例的最前面
class TestObject
{
public:
int x;
TestObject()
{
}
virtual void A()
{
}
virtual void B()
{
}
virtual void C()
{
}
};
int main()
{
TestObject* Object = new TestObject();
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/d987509e3ac54c37822eeec9c4abafdd.png)
##### 这个就是虚函数的地址