use*_*032 3 c# c++ inheritance types object-slicing
我无法理解导致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;
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,这个输出是"派生的".
如果我们删除f(),这将不再有效.输出是"Base".例:
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;
}
Run Code Online (Sandbox Code Playgroud)
我对此的理解是,具有虚函数会导致编译器向对象添加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());
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:我对C++部分的理解是否正确,以及当C++没有时,C#如何正确识别对象的类型?
正如你所说的那样:只有当你的类有一个virtual函数时,C++才会启用运行时多态性和类型识别,这意味着(在常见的实现中)a vptr被添加到类中(这与C++的哲学是一致的)你不付钱什么你不需要").
(以及对象的类型信息?)
然而,在类的vtable的第一个槽中存储指向RTTI记录的指针是很常见的 - 我说这是标准要求RTTI仅在类具有多态性时工作的原因之一(尽管像往常一样,这一切都依赖于编译器).
顺便说一句,RTTI不是虚拟分派正常工作所必需的,如果你调用一个虚函数,编译器必须做的就是call ptr用从vtable的正确槽中取出的指针来做; RTTI记录仅在检查类层次结构时dynamic_cast以及明确询问对象类型时使用typeid.
相反,在C#中,每个类默认都是多态的,并且具有与之关联的反射元数据,因此不需要做任何特定的事情来启用多态/类型识别.