Я экспериментирую с C ++, чтобы понять, как класс / структуры и их соответствующие объекты размещены в памяти, и я понял, что каждое поле класса / структуры является смещением в их соответствующем объекте (поэтому я могу иметь указатель на переменную-член).
Я не понимаю, почему, даже если у меня могут быть указатели на функции-члены, следующий код не работает:
struct mystruct
{
void function()
{
cout << "hello world";
}
int c;
};
int main()
{
unsigned int offset_from_start_structure = (unsigned int)(&((mystruct*)0)->c);
unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function); // ERROR - error C2276: '&' : illegal operation on bound member function expressionreturn 0;
}
Мой вопрос: почему линия
unsigned int offset_from_start_structure = (unsigned int)(&((mystruct*)0)->c);
компилирует и возвращает мне смещение поля «c» от начала структуры и строки
unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function);
даже не компилируется?
Функции-члены или указатели на них не хранятся в объекте. (virtual
функции обычно вызываются с помощью указателя, хранящегося в таблице, на которую объект имеет единственный указатель) огромный трата памяти. Обычно они хранятся в разделе памяти кода и известны компилятору. Предмет (*this
) обычно передается как невидимый параметр, чтобы функции знали, с каким объектом работать при их вызове.
Итак, с точки зрения непрофессионала, вы бы имели
0x10001000 void A::foo
.......... {code for A::foo}
а также
push a;
call A::foo (0x10001000)
pop a;
где a
это объект, который вы называете foo
на.
Указатели на функции-члены на практике не хранятся в объектах: в этом нет необходимости. Стандарт C ++ не определяет, как именно, например, виртуальные функции должны быть реализованы, но обычная практика для виртуальных функций-членов состоит в том, что каждый объект содержит указатель на таблицу указателей функций; этот указатель называется указатель vtable.
Вы можете попытаться заполучить «Внутри объектной модели C ++» Стэнли Липпман.
Или вы можете просто попытаться достать мой старый руководство по указателям, на которую когда-то ссылались из статьи-указателя Википедии, до того, как исчез мой тогдашний сайт.
Что касается второго вопроса, зачем брать адрес p->memberFunc
делает компилятор немного подавленным, хорошо, что выражение не имеет типа, это просто синтаксическая сущность, к которому вы можете применить список аргументов для вызова функции.
Для остроумия,
struct S
{
void foo() {}
};
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
S* p = 0;
typeid( &p->foo );
}
Компиляция:
[W: \ DEV \ тест] > g ++ foo.cpp foo.cpp: в функции 'int main ()': foo.cpp: 12: 17: ошибка: ISO C ++ запрещает принимать адрес связанной функции-члена для формирования указателя на функцию-член. Скажите 'S :: foo' [-fpermissive] foo.cpp: 12: 22: предупреждение: вычисленное значение не используется [-Wunused-value] foo.cpp: 12: 22: предупреждение: инструкция не действует [-Wunused-value] [W: \ DEV \ тест] > _