gpt4 book ai didi

C# 与 C++ - 类型、继承和 vtable

转载 作者:太空狗 更新时间:2023-10-29 19:49:21 28 4
gpt4 key购买 nike

我无法理解是什么导致了 C++ 和 C# 之间的差异。

首先我们有一个示例,其中基类包含一个虚函数。

class Base
{
protected:
int super;
public:
virtual int f() = 0;
};

class Derived : public Base
{
public:
int extraA;
int f(){ return 1; }
};

int main()
{
Derived *d = new Derived();

std::vector<Base*> v;
v.push_back(d);

for(int i=0; i < v.size() ;i++)
{
// Output "Derived"
std::cout << typeid(*v[i]).name() << std::endl;
}

return 0;
}

正如预期的那样,此输出是“Derived”。

如果我们删除 f(),这将不再有效。输出是“基础”。示例:

class Base
{
protected:
int super;
};

class Derived : public Base
{
public:
int extraA;
};

int main()
{
Derived *d = new Derived();

std::vector<Base*> v;
v.push_back(d);

for(int i=0;i<v.size();i++)
{
// Output "Base"
std::cout << typeid(*v[i]).name() << std::endl;
}

return 0;
}

我对此的理解是,拥有一个虚函数会导致编译器向对象添加一个 vptr,它指向 vtable。 vtable 包含要调用的正确函数的地址 (Derived::f()) -(以及对象的类型信息?)

现在进入有趣的部分 - 与 C# 的比较。在这里,“Base”和“Derived”基本上是类似于第二个 C++ 示例的空类:

public static void Main()
{
Derived d = new Derived();
IList<Base> v = new List<Base>();
mList.Add(d);

for (int i = 0; i < v.Count; i++)
{
// Output: "Derived"
System.Console.WriteLine(v.ElementAt(i).GetType());
}
}

因此我的问题是:我对 C++ 部分的理解是否正确,以及当 C++ 不正确时,C# 如何设法正确识别对象的类型?

最佳答案

正如您所说:C++ 仅在您的类具有 virtual 函数时启用运行时多态性和类型识别,这意味着(在常见实现中)添加了 vptr类(这与 C++ 的哲学“你不需要为你不需要的东西付费”是一致的)。

(As well as type information of the object?)

然而,通常将指向 RTTI 记录的指针存储在类的 vtable 的第一个槽中——我想说这就是为什么标准要求 RTTI 仅在类是多态(虽然,像往常一样,这一切都依赖于编译器)。

顺便说一下,R​​TTI 不是虚拟分派(dispatch)正确工作所必需的,如果你调用一个虚函数,编译器所要做的就是用从正确vtable 的插槽; RTTI 记录仅在检查 dynamic_cast 中的类层次结构以及通过 typeid 明确询问对象类型时使用。

相反,在 C# 中,每个类在默认情况下都是多态的,并且具有与其关联的反射元数据,因此无需执行任何特定操作来启用多态/类型识别。

关于C# 与 C++ - 类型、继承和 vtable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9727827/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com