Внутреннее представление объектов - PullRequest
3 голосов
/ 19 ноября 2011

Так что все это время я думал, что когда вы делаете что-то вроде ObjectA.field1, ObjectA похож на любое значение в стеке, и вы в основном получаете доступ к его полям.Теперь я просматривал заметки для класса о языках ООП и понял, что когда вы делаете ObjectA.field1, на самом деле происходит HEAP (адрес ObjectA) (field1), который возвращает вам значение поля field1.Это меня немного смущает.Может кто-нибудь сказать, почему происходит поиск, хотя у нас уже есть ценность объекта?Надеюсь, я смог объяснить ..

Ответы [ 2 ]

7 голосов
/ 20 ноября 2011

Объекты на самом деле не так волшебны.По сути, объект просто состоит из линейной коллекции всех его членов с неопределенным количеством отступов, окружающих члены.В плане компоновки класс C ++ по сути похож на структуру C:

struct Foo {
  int a;
  char b;
  std::string s;

  static long q;

  void bar() { print(s); log(a); }
  static void car() { }
}

На данный момент игнорируя функции-члены и статику, это можно выложить так:

+= class Foo =+
+-------------+  ---\   <---   Foo * p
|  int        |     s
+-------------+     i
|  char       |     z
+-------------+     e
| <padding>   |     o
+-------------+     f
| std::string |    (F
+-------------+     o
| <padding>   |     o)
+-------------+  ---/

Каждый объекткласса Foo хранится как это в памяти.Единственные дополнительные данные, которые нам нужны, - это статические члены, функции-члены и статические функции-члены.

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

+== static__Foo__q ==+
+--------------------+
|  long int          |
+--------------------+

Далее статические функции-члены - это просто обычные свободные функции:

void static__Foo__car() {  }

Наконец, функции-члены : по сути, это также обычные функции, хотя и с дополнительным параметром, который позволяет им находить элементы экземпляра:

void member__Foo__bar(Foo * p) { print(p->s); log(p->a); }

Единственное важное отличие состоит в том, что вы не можетеполучить обычный указатель свободной функции на функции-члены, поскольку фактическое имя функции реализации не раскрывается.Единственный способ обратиться к Foo::bar() - через функцию указателя на член void (Foo::*ptfm)() = &Foo::bar.Объекты-члены немного проще: вы можете либо получить нормальный указатель на них, например Foo x; int * p = &x.a;, но вы также можете сформировать указатель на член: int Foo::*ptm = &Foo::a;.

Затем, если у нас есть объектыFoo x, y, z;, мы можем использовать пары указателя экземпляра Foo * pi = &x; и указатели элементов int &Foo::* ptm = &Foo::a или void (Foo::*ptfm)() = &Foo::bar для доступа к соответствующему элементу данного экземпляра: целому числу pi->*ptm и функциизвоните (pi->*ptfm)() соответственно.(Да, ->* является оператором.)

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

3 голосов
/ 19 ноября 2011

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

...