Объекты на самом деле не так волшебны.По сути, объект просто состоит из линейной коллекции всех его членов с неопределенным количеством отступов, окружающих члены.В плане компоновки класс 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)()
соответственно.(Да, ->*
является оператором.)
(Свободная версия указателя функции не может существовать, поскольку полиморфные (виртуальные) функции требуют более сложного механизма диспетчеризации, чем простой фиксированный указатель на функцию.)