Где компилятор хранит методы для классов C ++? - PullRequest
5 голосов
/ 25 мая 2010

Это больше любопытство, чем все остальное ...

Предположим, у меня есть класс C ++ для Kitty:

class Kitty
{
    void Meow()
    {
        //Do stuff
    }
}

Размещает ли компилятор код для Meow () в каждом экземпляре Kitty?

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

Полагаю, это детали реализации, поэтому разные компиляторы могут работать по-разному.

Имейте в виду, я не рассматриваю статические или виртуальные методы здесь.

Ответы [ 6 ]

4 голосов
/ 25 мая 2010

В обычной реализации есть только одна копия любой данной функции. Связь между кодом и данными для данного экземпляра объекта устанавливается путем передачи скрытого параметра (обозначаемого в функции this), который является указателем на экземпляр объекта (и его данные).

Для виртуальных функций все становится немного более запутанным: каждый класс получает виртуальную таблицу, которая содержит набор указателей на виртуальные функции, а каждый объект получает указатель на виртуальную таблицу для своего класса. Виртуальные функции вызываются путем нахождения указателя vtable, просмотра правильного смещения и вызова функции, на которую указывает этот указатель.

3 голосов
/ 25 мая 2010

Я полагаю, что стандартный способ для методов экземпляра должен быть реализован как любой статический метод, только один раз, но с указателем this, переданным в определенный регистр или в стек для выполнения вызова.

2 голосов
/ 25 мая 2010

Поскольку у вас есть определение Meow внутри определения класса, Meow неявно встроено.

inline - подсказка компилятору о замене вызова фактическим содержимым функции. Но это только подсказка - компилятор может проигнорировать подсказку.

Если компилятор придерживается подсказки, каждый вызов будет заменен содержимым функции. Это означает, что компилятор будет генерировать код каждый раз, когда вызывается Meow вместо генерации вызова функции.

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

Наконец, давайте перейдем к объяснениям, где функция не является встроенной. В этом случае кодировщик должен убедиться, что определение присутствует только в одной единице перевода, и все вызовы будут отправлены в эту одну версию.

2 голосов
/ 25 мая 2010

Нет, это не так, как это делается.
Методы, отличные от virtual, точно такие же, как и любая другая функция, но с дополнительным аргументом для указателя this

Методы, которые virtual, вызываются с использованием v-таблицы . v-таблица - это список указателей на функции, которые хранятся рядом с данными объектов. В некотором смысле это ближе к тому, что вы описываете, но все же тело функции всегда одинаково для всех экземпляров объекта.
Это можно продемонстрировать, если в методе есть переменная static. Статическая переменная будет одинаковой для методов, вызываемых из разных экземпляров.

1 голос
/ 25 мая 2010

Нет, компилятор генерирует код для Meow только один раз, и каждый экземпляр Kitty использует, если член был скомпилирован вне строки. Если компилятор может и выбирает встроенную функцию, он дублируется в каждой точке использования (а не в каждом экземпляре Kitty).

0 голосов
/ 25 мая 2010

Компилятор создает запись для каждого класса (не объекта) внутри своей собственной структуры данных. Эта запись для класса содержит указатели на методы для этого класса.

Объект представлен в памяти как указатель на родительский класс и набор его полей экземпляра (поскольку они различны для каждого объекта.) Затем, когда вызывается метод, объект следует за указателем на своего родителя, который затем следует за указателем на соответствующий метод. Указатель на объект также предоставляется методу, который действует как указатель this.

Виртуальные методы немного сложнее, но они выполняются аналогичным образом.

Если вы хотите узнать больше, посмотрите, можете ли вы пройти курс изучения языков программирования.

Вот плохая попытка объяснить искусство ASCII:

 obj                        class
+------------+            +----------+
| ptrToClass |----------->| method1  | ----------> toSomewhere(ptrToObj)
|------------|            |----------|
| field1     |            | method2  | ----------> toSomewhereElse(ptrToObj)
+------------+            +----------+
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...