Почему нельзя получить шестнадцатеричное значение указателя
Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain
-
- Сообщения: 38
- Зарегистрирован: 21 июн 2004, 02:59
- Откуда: Saratov
- Контактная информация:
Почему нельзя получить шестнадцатеричное значение указателя на метод класса?
В книге Павловской Т.А. "Программирование на языке высокого уровня" этому дается следующее объяснение: "...в отличие от указателя на переменную или обычную функцию, указатель на метод не ссылается на определенный адрес памяти. Он больше похож на индекс в массиве, поскольку задает смещение. Конкретный адрес в памяти получается путем сочетания указателя на метод с указателем на определенный объект".
Но!!! Но ведь методы не дублируются! Копии полей (т.е. компонентных данных) - да, создаются для каждого экземпляра класса свои... Но методы-то! Они хранятся в единственном числе! Если же верить объяснению Павловской Т.А., то: 1) у нас имеется множество дублированных для каждого экземпляра класса методов, либо 2) непонятно тогда, каким образом смещения для методов ЛЮБЫХ объектов класса ОДНИ И ТЕ ЖЕ, хотя они(объекты класса), естественно, в оперативке в разных местах будут лежать...
Более правдоподобным мне кажется, что указатель на метод класса задает адрес в оперативной памяти необходимой нам компонентной функции, а когда мы вызываем ее (через имя объекта или указатель на объект), таким образом мы передаем ей еще и указатель this. И, все-таки, это не объясняет, почему же нельзя получить шестандцатеричное значение указателя на метод класса...
Так как же все на самом деле?
В книге Павловской Т.А. "Программирование на языке высокого уровня" этому дается следующее объяснение: "...в отличие от указателя на переменную или обычную функцию, указатель на метод не ссылается на определенный адрес памяти. Он больше похож на индекс в массиве, поскольку задает смещение. Конкретный адрес в памяти получается путем сочетания указателя на метод с указателем на определенный объект".
Но!!! Но ведь методы не дублируются! Копии полей (т.е. компонентных данных) - да, создаются для каждого экземпляра класса свои... Но методы-то! Они хранятся в единственном числе! Если же верить объяснению Павловской Т.А., то: 1) у нас имеется множество дублированных для каждого экземпляра класса методов, либо 2) непонятно тогда, каким образом смещения для методов ЛЮБЫХ объектов класса ОДНИ И ТЕ ЖЕ, хотя они(объекты класса), естественно, в оперативке в разных местах будут лежать...
Более правдоподобным мне кажется, что указатель на метод класса задает адрес в оперативной памяти необходимой нам компонентной функции, а когда мы вызываем ее (через имя объекта или указатель на объект), таким образом мы передаем ей еще и указатель this. И, все-таки, это не объясняет, почему же нельзя получить шестандцатеричное значение указателя на метод класса...
Так как же все на самом деле?
Прости, что мне так показалось, но, по моему, это просто блеск знаний или что-то в этом роде. Скажи, а для чего это реально надо?
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
На самом деле всё обстоит именно так, как ты и думаешь. То есть методы класса не дублируются, а вызывая метод класса через точку после некого объекта, ты на самом деле генерируешь вызов метода с дополнительным неявным параметром CYourClassName * const this.
Вопросы возникают другие: Почему ты не можешь получить указатель на метод? (Как ты пытался это делать?) Почему он должен быть именно шестнадцатиричный? И вообще кто такой Павловский?
Вопросы возникают другие: Почему ты не можешь получить указатель на метод? (Как ты пытался это делать?) Почему он должен быть именно шестнадцатиричный? И вообще кто такой Павловский?

Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Это про COM или про обычные классы??
*provided AS IS
-
- Сообщения: 38
- Зарегистрирован: 21 июн 2004, 02:59
- Откуда: Saratov
- Контактная информация:
Это мне известно. Интересует же меня несколько иное...Romeo писал(а):На самом деле всё обстоит именно так, как ты и думаешь. То есть методы класса не дублируются, а вызывая метод класса через точку после некого объекта, ты на самом деле генерируешь вызов метода с дополнительным неявным параметром CYourClassName * const this.
...ммм... наверное, я недостаточно четко сформулировал вопрос. Да, я могу получить указатель на метод, и с помощью этого указателя вызвать необходимую компонентную функцию. Тут трудностей не возникает. Они появляются, когда я пытаюсь узнать численное значение этого указателя - не важно, будет ли это значение шестандцатеричным, десятичным и т.п. Меня интересует, собственно, вот что: ЧТО ЯВЛЯЕТСЯ ЗНАЧЕНИЕМ УКАЗАТЕЛЯ НА МЕТОД КЛАССА? Адрес в памяти этого самого метода? Смещение? (от чего в таком случае?) Смещение какого-нибудь указателя в таблице? (тогда что это за таблица?) ...любой указатель можно привести к типу void*, хотя для того, чтобы получить его значение в большинстве случаев этого делать не требуется(за исключением указателя на char, потому что при попытке вывести его значение напрямую у нас распечататеся строка, адресуемая им). В случае с указателем на метод класса... хмм... это не получилось...Romeo писал(а): Вопросы возникают другие: Почему ты не можешь получить указатель на метод? (Как ты пытался это делать?) Почему он должен быть именно шестнадцатиричный?
Не "Павловский", а "Павловская" - Павловская Татьяна Александровна, профессор кафедры информатики и прикладной математики Санкт-Петербургского государственного университета информационных технологий, механики и оптики (СПбГУИТМО), кандидат технических наук в области систем автоматизации проектирования. Автор ряда работ по Си++, одну из которых я и процитировал...Romeo писал(а): И вообще кто такой Павловский?![]()
Раз идет разговор про COM.
На все, что находится в памяти можно получить указатель, в т.ч. и на метод. Когда ты вызываешь метод ты грубо говоря (без учета диспинтерфейсов и т.п.) вызываешь функцию по определенному смещению из vtbl. Адрес этой функции вроде как и искомый указатель
На все, что находится в памяти можно получить указатель, в т.ч. и на метод. Когда ты вызываешь метод ты грубо говоря (без учета диспинтерфейсов и т.п.) вызываешь функцию по определенному смещению из vtbl. Адрес этой функции вроде как и искомый указатель

*provided AS IS
Павловская полу...права. Она правильно _ставит_ вопрос, но совершенно неправильно _отвечает_ на него.
Ответ на вопрос-то очевиден вполне - достаточно для небольшой программки попросить у
компилятора вывод ассемблерного листинга...Более подробно это в рассылке про COM рассмотрено
http://developing.ru/com/index.html В статье "введение в теорию компиляции и выведение из неё"...
Вкратце всё вот как выглядит. Любой метод - статическая сущность. Метод отличается от свободной функции только
одним - он получает скрытый параметр this, который есть указатель на структуру данных экземпляра класса.
Если есть возможность вычислить адрес функции, то почему нельзя вычислить адрес метода? Тем не менее, вызвать
"так просто" нестатический метод не получается - ему требуется this. Поэтому где-то в недрах MSDN есть примечание,
что указатель на метод - не четыре байта, а восемь. Т.е. не один адрес, а - два... Один из которых - "адрес функции",
а второй - "адрес this". Но указатель на статический метод эквивалентен указателю на свободную функцию, у него ведь нет
this?
Вообще же, ссылка на this экземпляра передаётся через регистр BX, т.е. в терминах языка высокого уровня нестатический
метод не вызвать "вручную", как свободную функцию с дополнительным параметром. А на ассемблере - запросто.
Ответ на вопрос-то очевиден вполне - достаточно для небольшой программки попросить у
компилятора вывод ассемблерного листинга...Более подробно это в рассылке про COM рассмотрено
http://developing.ru/com/index.html В статье "введение в теорию компиляции и выведение из неё"...
Вкратце всё вот как выглядит. Любой метод - статическая сущность. Метод отличается от свободной функции только
одним - он получает скрытый параметр this, который есть указатель на структуру данных экземпляра класса.
Если есть возможность вычислить адрес функции, то почему нельзя вычислить адрес метода? Тем не менее, вызвать
"так просто" нестатический метод не получается - ему требуется this. Поэтому где-то в недрах MSDN есть примечание,
что указатель на метод - не четыре байта, а восемь. Т.е. не один адрес, а - два... Один из которых - "адрес функции",
а второй - "адрес this". Но указатель на статический метод эквивалентен указателю на свободную функцию, у него ведь нет
this?
Вообще же, ссылка на this экземпляра передаётся через регистр BX, т.е. в терминах языка высокого уровня нестатический
метод не вызвать "вручную", как свободную функцию с дополнительным параметром. А на ассемблере - запросто.
Привожу типовой пример вызова метода из ассемблера (вырезано из документации к MASM32):
1)edx + 0 - это намек на то, что в vtbl QueryInterface - первый метод (AddRef уже будет edx + 4, Release edx + 8)
2)dword ptr [edx] - искомое "шестнадцатиричное" :) значение указателя.
3)this как бы учавствует. но косвенно конечно
PS. Павловской - привет :)
Пояснения от меня:
... вырезано ...
When the client makes a call to the COM library to create a COM object, it passes in the address where it wants the object pointer to be placed. This initial pointer is generically referred to as "ppv," from the C++ speak "pointer to pointer to (void)," where (void) means an unspecified type. It holds the address of another pointer ("pv"), and this pointer refers to a whole table of pointers, one table entry for each function of the interface.
For example, say we used CoCreateInstance and successfully got an interface pointer ppv, and wanted to see if it supports some other interface. We can call its QueryInterface method and request a new ppv (ppv2, pointer to an Interface) to the other interface (pIID, pointer to a Interface Identifying GUID) we are interested in. In C, QueryInterface has a prototype that would look like so:
(HRESULT) SomeObject::QueryInterface (this:pObject, IID:pGUID, ppv2:pInterface)
Such a call would look like this:
; get pointer to the object
mov eax, ppv
; and use it to find the interface structure
mov edx, [eax]
; push the function parameters onto the stack
push OFFSET ppv2
push OFFSET IID_ISomeOtherInterface
push dword ppv
; and then call that method
call dword ptr [edx + 0]
... вырезано ...
1)edx + 0 - это намек на то, что в vtbl QueryInterface - первый метод (AddRef уже будет edx + 4, Release edx + 8)
2)dword ptr [edx] - искомое "шестнадцатиричное" :) значение указателя.
3)this как бы учавствует. но косвенно конечно
PS. Павловской - привет :)
*provided AS IS
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Женщин не стоит подпускать к компьютеру и тем более писать труды по С++ 

Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.