对于其clas(子)具有单继承的对象,通常需要多少个vptrs,其基类为多个继承base1和base2.确定对象提供了多少个vpt的策略是什么,它提供了几个单继承和多继承.虽然标准没有指定vptrs,但我只是想知道一个实现如何实现虚函数.
我试图通过虚拟表和继承来解决一些低级别的问题.
通过继承两个类并添加新的虚函数来创建新类时,vptr将存储在哪里?
在我看来,编译器在这种情况下执行一些'vptr-optimization'.而我正想弄明白.
假设,我们有以下结构:
struct A
{
int a;
virtual void fa();
};
struct B
{
double b;
virtual void fb();
};
struct C : A, B
{
char c;
virtual void fa();
virtual void fb();
virtual void fc();
};
Run Code Online (Sandbox Code Playgroud)
在86的情况下和对齐= 4,A并且B在存储器中看起来像这样:
+------+------+
A: | vptr | a |
+------+------+
sizeof(A) = 4 + 4 = 8
+------+------+------+------+
B: | vptr | b |
+------+------+------+------+
sizeof(B) = 8 + 8 = 16
Run Code Online (Sandbox Code Playgroud)
但是当我尝试重新组装时C,我得到了这个:
+------+------+------+------+------+------+------+ …Run Code Online (Sandbox Code Playgroud) 据我所知,virtual函数指针表在对象中的位置取决于编译器.
是否有任何利弊将这个指针放在对象的开头和结尾处,反之亦然?
我对C++和Java中的虚拟机制有一些困惑.以下程序的输出是不同的.我无法理解为什么?
在Java中:
class Base
{
Base()
{
show();
}
public void show()
{
System.out.println("Base::show() called");
}
}
class Derived extends Base
{
Derived()
{
show();
}
public void show()
{
System.out.println("Derived::show() called");
}
}
public class Main
{
public static void main(String[] args)
{
Base b = new Derived();
}
}
Run Code Online (Sandbox Code Playgroud)
输出是:
Derived::show() called
Derived::show() called
Run Code Online (Sandbox Code Playgroud)
在C++中,输出如下:
#include<bits/stdc++.h>
using namespace std;
class Base
{
public:
Base()
{
show();
}
virtual void show()
{
cout<<"Base::show() called"<<endl;
}
};
class Derived : …Run Code Online (Sandbox Code Playgroud) 我正在尝试实现类似于此处描述的系统.也就是说,(ab)使用vtable修改来改变运行时的对象行为.这是我尝试在我正在开发的C++项目中创建高效类型通用包装器的一部分.
例如,如果您无法访问它,请使用memcpy()和this指针复制vtable :
void setType( const DataType& newType )
{
memcpy( this, &newType, sizeof(DataType) );
}
Run Code Online (Sandbox Code Playgroud)
但是,我对此方法存在一个问题:我没有目标类的对象来复制vtable,并且不希望创建一个,因为某些类型的构造成本很高.
有没有办法访问vtable,它将被放置到给定类的对象中而没有该类的对象?
如果它在某种程度上是可移植的,那将是更好的,但我基本上已经辞职,因为它是特定于编译器的; 因此,如果没有其他选项,只接受GCC/G ++方法.我们还假设我只关心在相当标准的操作系统和体系结构上构建它.
我正在使用C++ 11,应该以某种方式帮助它.
编辑:我想完全清楚,我知道这种行为是多么危险.我对这个想法更感兴趣,也许它在非常有控制的情况下应用它的狭隘应用,而不是我对生产软件的好主意,尽管我的介绍可能会提出建议.
这个问题特别是关于非便携式 MSVC ABI 的东西。
我正在尝试typeid用明显不可移植但又不神奇的 C++编写等效的C++。对于 Itanium ABI(在 Linux/Mac 上使用),它非常简单:
const std::type_info& dynamicast_typeid(void *mdo)
{
std::type_info **vptr = *reinterpret_cast<std::type_info ***>(mdo);
std::type_info *typeinfo_ptr = vptr[-1];
return *typeinfo_ptr;
}
Run Code Online (Sandbox Code Playgroud)
所以现在我正在查看 64 位 MSVC ABI,并且该死的,我被难住了。对于非常简单的类,那些以 vfptr 开头的偏移量为 0 的类,它几乎和 Itanium 一样简单:
const std::type_info& dynamicast_typeid(void *mdo)
{
int *rtti_complete_object_locator = ((int ***)mdo)[0][-1];
char *result = (char *) rtti_complete_object_locator;
result -= rtti_complete_object_locator[5];
result += rtti_complete_object_locator[3];
return *(std::type_info*)result;
}
Run Code Online (Sandbox Code Playgroud)
(此代码基于Wine 项目的__RTtypeid.)
问题是某些 C++ 类不是以偏移量 0 处的 vfptr 开头!有时它们以 vbptr …
我知道,如何实现虚函数调用解析不是C++标准的一部分,也不是说有关vptr或v-table的任何内容,但请允许我在这里提出这个问题.
我听说v-table是编译器用来实现虚函数调用解析的常用技术.我对此的理解是每个进程每个类只需要一个虚拟表.
我想知道的是,什么时候为一个类创建了v-table?
是否在第一次在进程空间中创建给定类型(需要v表)的类时?
在该进程空间中所有其他随后创建的该类型的对象是指已创建的v表?
什么时候会删除这个v表?
我很抱歉,如果这是太主观或讨论类型的问题,但这些问题在我的脑海中徘徊了一段时间,我觉得它可以在这里问.
假设我有两个类继承具有纯虚函数的基类。这两个类都实现了该函数的自己的版本,但是不添加其他成员变量,因此它们具有相同的大小。现在有时候,在程序执行的中间,我想将一个类转换为另一个类,而不复制其所有数据。所以基本上我想让它使用其他类的虚拟表。有便携式的方法吗?
这是关于vtables的程序.我对vtable和v-pointers的理解是正确的.
Class B
{
public:
virtual Void Hello()
{
cout<<"Hello Base";
}
};
class D: public B
{
public:
virtual void Hello()
{
cout<<"Hello Derived";
}
};
int main(int argc, char* argv[])
{
D *d1 = new D();
D *d2 = new D();
D *d3 = new D();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在我看来,将有两个vtable,只有一个vptr.我对吗?
我认为sizeof(Base)应该是12。为什么是16?
没有虚函数,我得到4和8。
class Base{
public:
int i;
virtual void Print(){cout<<"Base Print";}
};
class Derived:public Base{
public:
int n;
virtual void Print(){cout<<"Derived Print";}
};
int main(){
Derived d;
cout<<sizeof(Base)<<","<<sizeof(d);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
预期结果?12?16
实际结果?16?16