我无法理解导致 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;
}
我对此的理解是,拥有一个虚函数会导致编译器向该对象添加一个指向 vtable 的 vptr。 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# 如何正确识别对象的类型?
正如您所说:只有当您的类具有virtual
函数,这意味着(在常见的实现中)vptr
添加到类中(这与 C++ 的哲学“你不需要为不需要的东西付费”是一致的)。
(以及对象的类型信息?)
然而,通常将指向 RTTI 记录的指针存储在类的 vtable 的第一个槽中 - 我想说,这就是标准要求 RTTI 仅在类是多态的情况下才起作用的原因之一(尽管,像往常一样,这一切都取决于编译器)。
顺便说一下,RTTI对于虚拟调度正常工作来说并不是必需的,如果你调用一个虚函数,编译器所要做的就是做一个call ptr
从 vtable 的正确槽中取出指针; RTTI 记录仅在检查类层次结构时使用dynamic_cast
当通过以下方式明确询问对象的类型时typeid
.
相反,在 C# 中,默认情况下每个类都是多态的,并且具有与其关联的反射元数据,因此无需执行任何特定操作即可启用多态性/类型识别。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)