C # против C ++ - Типы, наследование и vtable - PullRequest
3 голосов
/ 16 марта 2012

У меня проблемы с пониманием того, что вызывает эту разницу между 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. В таблице содержится адрес правильной вызываемой функции (Derived :: f ()) - (а также информация о типе объекта?)

Теперь для интересной части - Сравнение с C #. Здесь «Base» и «Derived» - это в основном пустые классы, похожие на 2-й пример 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 ++ нет?

Ответы [ 3 ]

6 голосов
/ 16 марта 2012

Это как вы говорите: C ++ включает полиморфизм во время выполнения и идентификацию типа только тогда, когда в вашем классе есть функция virtual, что означает, что (в общих реализациях) к классу добавляется vptr (это согласуется с философией C ++ «Вы не платите за то, что вам не нужно»).

(а также информация о типе объекта?)

Тем не менее, обычно указатель на запись RTTI хранится в первом слоте виртуальной таблицы класса - и я бы сказал, что это одна из причин, почему стандарт требует, чтобы RTTI работал только в том случае, если класс полиморфный (хотя, как обычно, все это зависит от компилятора).

Кстати, RTTI не обязателен для корректной работы виртуальной диспетчеризации, если вы вызываете виртуальную функцию, все, что нужно сделать компилятору, это сделать call ptr с указателем, взятым из правильного слота vtable; запись RTTI используется только при проверке иерархии классов в dynamic_cast и при явном запросе типа объекта через typeid.

В C # вместо этого каждый класс по умолчанию является полиморфным и с ним связаны метаданные отражения, поэтому нет необходимости делать что-то конкретное для включения идентификации полиморфизма / типа.

3 голосов
/ 16 марта 2012

В C ++ информация о типах среды выполнения действительно работает только с типами, в которых родительский класс в вашей иерархии имеет хотя бы одну виртуальную функцию.Указатель «vtable» указывает на таблицу виртуальных функций, а также идентифицирует тип.(В принципе, по крайней мере, я не могу вспомнить, насколько строго стандарт определяет, как должны реализовываться виртуальные функции.) Если виртуальных функций нет вообще, эта информация не используется для эффективности.информация всегда есть, виртуальные функции или нет.

2 голосов
/ 16 марта 2012

Различия между C ++ и C # являются глубокими и обширными, и это всего лишь сноска в энциклопедии различий.

А именно, в C # каждый класс должен наследовать от Object, который имеет виртуальные функции, поэтомуC # никогда, никогда не бывает в случае, когда объект не имеет виртуальных функций.C ++, однако, делает.Обычно.Так что в C ++ некуда поместить идентификационную информацию типа времени выполнения.

...