虚拟表是否需要C++
Is virtual table necessary for C++?
我最近对虚拟表有疑问C++。
为什么C++使用虚拟表?
=>因为编译器不知道C++实际的函数地址
--->为什么?
=>因为编译器不知道C++确切的类型(猫?狗?动物?指针"panimal"指向的对象
---为什么?编译器可以通过任何方式找出对象类型吗?
=>是的,我认为编译器可以通过跟踪对象类型来实现它。
让我们考虑对象指针获取其值的来源。 确实有 2 个来源。
- 另一个指针
- 类实例的地址"另一个指针"的价值从何而来?最终,有一个指针从"类实例"中获取其值。
因此,通过向后跟踪赋值线程到原始源对象
=>编译器能够找出指针的确切类型。
=>编译器知道被调用的确切函数的地址
=>不需要虚拟表。
对象类型跟踪保存每个类实例的虚拟表内存和虚拟表指针。
对象类型跟踪在哪些地方不起作用?
库链接。
如果库函数返回基类指针,则编译器无法追溯到原始源对象。编译器可能可以适应库代码和非库代码。对于导出的库类,请使用虚拟表。对于其他类,只需跟踪对象类型以节省内存。
我不确定上述陈述是否有错误,如果有的话,请指出。提前感谢~
在某些情况下,是的,编译器可以在编译时找出指针指向的类型。构建一个无法构建的案例非常容易。
int x;
cin >> x;
Animal* p;
if (x == 10)
p = new Cat();
else
p = new Dog();
如果编译器在所有情况下都可以证明对象的类型,则可以根据 as-if 规则从其生成的代码中自由删除虚拟表。
编译器能够找出指针的确切类型。
是的,但是您希望它在运行时如何调用正确的函数?编译器知道,但 c++ 没有虚拟机来告诉它在运行时传递的对象的类型,因此,需要继承类型的虚拟函数的 vtable。您是否希望编译器为导致每个虚拟函数执行的所有不同代码路径创建代码,以便它在运行时调用正确的函数?如果可能的话,这将导致更大的二进制文件。
在这个例子中,很明显,无论编译器可以进行什么静态代码分析,在ptrA->f()调用的实际方法只能在运行时知道。
#include <sys/time.h>
#include <iostream>
#include <stdlib.h>
struct A {
virtual int f()
{
std::cout<<"class An";
}
};
struct B: public A {
int f()
{
std::cout<<"class Bn";
}
};
int main()
{
A objA;
B objB;
A* ptrA;
timeval tv;
gettimeofday(&tv, NULL);
unsigned int seed = (unsigned int)tv.tv_sec;
int randVal = rand_r(&seed);
if( randVal < RAND_MAX/2)
{
ptrA=&objA;
}
else
{
ptrA=&objB;
}
ptrA->f();
return 0;
}`
- 在提升multi_index容器中,是否定义了"default index"?
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 检查输入是否不是整数或数字
- 是否可以初始化不可复制类型的成员变量(或基类)
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 此代码是否违反一个定义规则
- 是否需要删除包含对象的"pair"?
- 是否可以从int转换为enum类类型
- 无论条件是否为true,if总是在c++中执行
- 如何找到大小'x'数组是否完全填充,在C++?
- 检查值是否在集合p1和p2中,但不在p3中
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 检查 std::shared_ptr<> 的当前底层类型是否为 T
- 在c++中检查长方体是否尽可能快地重叠(无迭代)
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- C/C++预处理器是否可以检测一些编译器选项
- 是否可以用"iostream"包装现有的TCP/OOpenSSL会话