C++虚函数,虚函数表指针和虚函数表详解

C++虚函数,虚函数表指针和虚函数表详解,第1张

class Occupation
{
public:
	Occupation(){};
	virtual void show() { std::cout << "Occupation::show()" << std::endl; }
	virtual void show(int) { std::cout << "Occupation::show(int)" << std::endl; }
private:
	int name_;
};
虚函数

被virtual关键字修饰的函数称为虚函数。

虚函数表 vftable

一个类中,存在被virtual修饰的成员方法,那么,编译器在编译该类时,会产生一张虚函数表,用来记录类中虚函数的地址;

虚函数表是属于该类型的,该类型实例化的所有对象共享该虚函数表;

虚函数表存放在进程虚拟地址空间的.rodata段,可读不可写。

虚函数表地址 vfptr

当我们使用该类实例化一个对象时,该对象的内存中前会多出四个字节,存放vfptr,而vfptr指向的是该类的虚函数表vftable。

int main()
{
	Occupation o;
	std::cout << sizeof o << std::endl;  // 8
	return 0;
}
虚函数表中的内容
  • RTTI: run-time type information,属于哪个类的虚函数表,就存储了哪个类的类型的常量字符串的地址,比如Occupation类的RTTI为 "Occupation" 的地址;
  • vfptr在对象内存中的偏移值:一般为0
  • 该类的虚函数的函数地址
继承体系中:重写/覆盖
class Student : public Occupation
{
public:
	Student(){};
	void show() { std::cout << "Student ::show()" << std::endl; }
	std::string name() { return name_; }
};

如果派生类中存在方法A和基类的虚函数B的函数名,返回值,以及参数列表一致时,派生类的该方法会自动被处理成虚函数。

并且,将继承来的基类的虚函数表中的B的函数入口地址,覆盖为A的入口地址,该过程称为覆盖,或者也叫重写。

Occupation类的虚函数表的内容:

Student类的虚函数表的内容:

动态绑定:
int main()
{
    Student s;
	Occupation *op = &s;
    op->show();
    op->show(100);
	return 0;
}

判断何时静态绑定合适动态绑定:

  1. 指针op是基类的指针,如果基类Occupation的show()不是一个虚函数,那么将进行静态绑定,即在编译期就确定调用的是基类的show().
call Occupation::show()

因为指针op的类型是Occupation,所以能访问的内容是派生类继承来的基类的那部分内容。

  1. 如果基类Occupation的show()是一个虚函数,那么将进行动态绑定,此时,生成的汇编指令大概是:
move eax, dword ptr[op]
move ecx, dword ptr[eax]
call exc

寄存器ecx中值是多少,只有在运行的时候才能知道,所以称之为动态绑定。

存在虚函数是对于指针变量的类型识别的影响:
int main()
{
    Student s;
	Occupation *op = &s;

    std::cout << typeid(op).name() << std::endl;
    std::cout << typeid(*op).name() << std::endl;
	return 0;
}

输出结果:

P10Occupation
7Student

结果分析:

第一个打印:
C++是静态语言,定义时是什么类型,运行时就是什么类型,不会变,所以没问题op是Occupation类型的指针;

第二个打印:
上面我们知道op是Occupation类型的指针,我们需要判断*op是什么类型时,需要看Occupation中有没有虚函数

如果没有虚函数,那么*op识别的就是编译期的类型,即Occupation类型;
如果有虚函数,*pb识别的时运行时的类型,即RTTI类型。op指向的是一个派生类对象s,根据s的前四个字节访问到的时派生类的虚函数表,派生类的虚函数表中存放的是派生类的类型,即"class Student"。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/676224.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-19
下一篇 2022-04-19

发表评论

登录后才能评论

评论列表(0条)

保存