#c #object #memory-layout
Вопрос:
Насколько я понимаю, все функции-члены будут созданы в отдельной памяти при определении класса и являются общими для всех объектов. И только переменные-члены создаются индивидуально для каждого объекта. Но как функция-член выполняется при вызове с использованием объекта?
Где будет храниться адрес для этих функций-членов?
class B{
public:
int a;
void fun(){
}
};
int main(){
B b;
std::cout<<sizeof(b)<<std::endl;
}
Если я выполню эту программу, я получу результат в виде 4(который предназначен только для переменной-члена). Но вызов b.fun() правильно вызывает свою функцию-член. Как он вызывает, не сохраняя свой адрес внутри объекта? Где хранятся адреса функций-членов?
Есть ли что-нибудь похожее на схему памяти класса, в которой будут храниться эти адреса?
Комментарии:
1. Ваша сегодняшняя еда в Google — «искажение символов c «.
2. @SamVarshavchik Я не думаю, что искажение даст самый прямой ответ.
3. Допустим , вы создаете функцию, не являющуюся членом
void fun(B *b) {}
, и делаетеfun(b);
это . Теперь вас не удивляет, что несвязанная функция не влияет на размерB
? Функции-члены работают аналогично, просто синтаксис их вызова отличается.4. Детали различаются в разных реализациях, но обычно невиртуальная функция-член вызывается так же, как и любая другая функция (со скрытым
this
параметром). Обычно адрес вызываемой функции «сохраняется» в самой инструкции вызова в качестве непосредственного операнда. Для указателя функции в другом месте не требуется места; в частности, он не хранится в макете памяти объектов этого типа. Если вы хотите узнать о внутренних компонентах, укажите свой компилятор / архитектуру / ОС / ABI / модель кода / и т.д.
Ответ №1:
Невиртуальные функции-члены чрезвычайно похожи на обычные функции, не являющиеся членами, с единственной разницей между ними, заключающейся в указателе на экземпляр класса, передаваемый в качестве самого первого аргумента при вызове.
Это делается автоматически компилятором, поэтому (в псевдокоде) ваш вызов b.fun()
может быть скомпилирован в
B::Fun(amp;b);
Где B::Fun
можно рассматривать как обычную функцию. Адрес этой функции не обязательно должен храниться в реальном объекте (все объекты этого класса будут использовать одну и ту же функцию), и, следовательно, размер класса не включает его.
Комментарии:
1. Несвязанное примечание: То, как именно
this
входит в метод, не очень четко определено стандартом C . То, что описано выше, является самым прямым способом сделать это и единственным способом, который я видел в дикой природе. Ноthis
это может быть скрытый последний параметр или перенесенный в метод с помощью магии эльфов. Дело в том, что вам на самом деле все равно, какthis
это проявляется в методе, пока это так.
Ответ №2:
Есть ли что-нибудь похожее на схему памяти класса, в которой будут храниться эти адреса?
Есть для объявленных функций virtual
, да. В этом случае адреса указанных функций хранятся в таблице и просматриваются во время выполнения. Это, в свою очередь, позволяет вашему коду отправлять правильную функцию в зависимости от типа объекта при вызове функции.
Невиртуальные функции таким образом не работают. Они хранятся так же, как и свободные (т. е. не являющиеся членами) функции, с именем функции, префиксом имени класса. Никакого места для хранения внутри самого объекта не требуется.
В обоих случаях this
вызываемой функции передается скрытый указатель. Это то, что «соединяет» его с вашим объектом.