编程语言
首页 > 编程语言> > C#vs C – 类型,继承和vtable

C#vs C – 类型,继承和vtable

作者:互联网

我无法理解导致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;
}

正如预期的那样,这个输出是“派生的”.

如果我们删除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;
}

我对此的理解是,具有虚函数会导致编译器向对象添加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才能启用运行时多态性和类型识别,这意味着(在通常的实现中)将vptr添加到类中(这与C的哲学是一致的“你不是支付你不需要的东西“).

(As well as type information of the object?)

然而,在类的vtable的第一个槽中存储指向RTTI记录的指针是很常见的 – 我说这是标准要求RTTI仅在类具有多态性时工作的原因之一(尽管像往常一样,这一切都依赖于编译器).

顺便说一句,RTTI不是虚拟分派正常工作所必需的,如果你调用虚函数,编译器必须做的就是用从vtable的正确槽中取出的指针来调用ptr; RTTI记录仅在检查dynamic_cast中的类层次结构时以及通过typeid明确询问对象类型时使用.

相反,在C#中,每个类默认都是多态的,并且具有与之关联的反射元数据,因此不需要做任何特定的事情来启用多态/类型识别.

标签:c,c-2,types,inheritance,object-slicing
来源: https://codeday.me/bug/20190716/1481259.html