网站排名怎么做,wordpress pdf缩略图不显示,电脑上怎么做网页,国内哪个应用商店app最全虚函数
虚函数的实现
当调用一个虚函数时#xff0c;一般都是使用了virtual table和virtual table pointer#xff0c;简称vtbl和vptr#xff1a;
vtbl
一个函数指针数组。
在程序中#xff0c;一个类凡是声明或继承了虚函数#xff0c;都有一个vtbl#xff0c;是指…虚函数
虚函数的实现
当调用一个虚函数时一般都是使用了virtual table和virtual table pointer简称vtbl和vptr
vtbl
一个函数指针数组。
在程序中一个类凡是声明或继承了虚函数都有一个vtbl是指向虚函数实现体的指针。例如
class C1
{
public:C1();virtual ~C1();virtual void f1();virtual int f2(char c) const;virtual void f3(const string s);void f4() const;...
};
//虚函数按照其声明顺序放于vtbl表中
//vtbl数组中的每一个元素对应一个函数指针指向该类的虚函数//如果C2继承自C1重新定义某些继承而来的虚函数并加入新的虚函数:
class C2 : public C1
{
public:C2(); //非虚函数virtual ~C2(); //重定义函数virtual void f1(); //重定义函数virtual void f5(char* str); //新的虚函数...
};
//此时C2的vtbl包括没有被C2重定义的C1虚函数的指针f2、f3vptr
凡是声明了虚函数的类的对象都含有一个隐藏的数据成员指向对应的类的virtual table称为vptr。
虚函数的调用
通过对象的 vptr 找到类的 vtbl。这是一个简单的操作,因为编译器知道在对象内 哪里能找到 vptr(毕竟是由编译器放置的它们)。因此这个代价只是一个偏移调整(以得到 vptr)和一个指针的间接寻址(以得到 vtbl)。找到对应 vtbl 内的指向被调用函数的指针。这也是很简单的, 因为编译器为每个虚函数在 vtbl 内分配了一个唯一的索引。这步的代价只是在 vtbl 数组内 的一个偏移。调用第二步找到的的指针所指向的函数。
虚函数的成本 虚函数的第一个成本 你必须为每个拥有虚函数的类耗费一个virtual table空间其大小视虚函数的个数而定包括继承而来的。 虚函数的第二个成本 你必须在每一个拥有虚函数的对象内付出“一个额外指针”的代价。 虚函数的第三个成本 你放弃了使用内联函数。
参考C虚函数实现原理与代价
多重继承
每个对象含有多个vptr针对不同的父类vtbl子类产生一个特殊的vtbl。
虚基类
D-B-AD-C-A会导致A的字段在D中有两份这显然不合理。为了解决这个问题使用虚拟继承BC虚继承A大多数编译器会利用这样的机会来减少编译器的负担。。
运行时类型识别RTTI
C提供关键字typeid 获取类的type_info对象一个类对应于一个type_info对象类及其所有的对象共享一份RTTI信息。
RTTI的设计理念是根据class的vtbl来实现。
总结
理解虚函数、多重继承、虚基类及RTTI的成本很重要。 但你必须知道如果你需要这些功能就要忍受这些成本世事难两全。有时你确实想要回避编译器生成的服务例如隐式vptr和“指向虚基类”的指针会造成“将C对象存储于数据库”和“跨进程移动C对象”困难度提高所以你希望有某种方法模拟这些性质。不过从效率上来讲自己写的不可能比编译器生成的更好。