![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Да, именно об этом я и спрашивал: что через один указатель мы можем получать доступ как к методам наследника, так и к методам родителя(лей). Отчасти поэтому и выбрал пример с множественным наследованием -- яснее видно. Теперь, когда мы говорим об одном и том же -- повторю. Физически A::f(), B::f() и C::f()(если есть) компилятор располагает в памяти друг за другом? Т.к. благодаря этому приведение указателя на наследник к указателю на родителя имеет смысл. Т.е. при одиночном наследовании -- все так, как я написал? А при множественном? |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
нет.. 1. не обязательно друг за другом.. 2. функции вообще может не существовать в машинном коде 3. НЕ благодаря этому приведение имеет смысл Добавлено через 13 минут и 37 секунд нет. Сути Вы не написали.. то что адрес при преобразовании не меняется, нам роли не играет.. Вот еще один пример :
т.е когда мы явно не указываем каую функцию мы хотим вызвать, еще на стадии компиляции заменяется a.f (); на a.A::f(); b.f(); на b.B::f(); потому как компилятор обладает всей необходимой инфой для этого на тот момент времени. |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Значит в памяти могут располагаться так (х - какая-либо другая инфа; С -наследник А и В): xx[A::f()]xxxxxxxx[B::f()]xxxxx[C::f()]xxx а не так: ххххххxx[A::f()][B::f()][C::f()]xxxххххххх Тогда при приведении: 1. компилятор должен определить, где начинается, например, А и положить в указатель адрес на область А. 2. можно привести указатель с С на указатель не только к ео родителям А, В, а к любому другому. Например, к какому-нибудь Е, который от А и В вообще не наследует. Это сообщение отредактировал(а) Gunslinger - 14.1.2010, 17:16 |
|||
|
||||
| baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
Gunslinger, адрес функции-члена не вычисляется при вызове, он известен во время компиляции. поэтому совершенно неважно где эти функции в памяти расположены. более того, часть функций класса может быть в одной dll, другая часть - в другой.
с наследованием это никак не связано. исключение составляют виртуальные функции, но это отдельная тема. функция-член работает с данными объекта, для которого вызвана, при помощи указателя this, передаваемого неявно. вот пример:
Добавлено через 7 минут и 17 секунд
Технически можно. Практически не нужно. ЯВУ существует как раз для того, что бы не думать об адресах и т.п., а думать в терминах задачи |
||||
|
|||||
| mes |
|
||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
зачем компилятору адрес, если есть имя.. Пусть линкер думает что и куда соединять и по какому адресу располагать
можно.. закрыв глаза компилятору..но тогда вся ответсвенность лежит на программисте.. если структура будет подходящей (ну а значит у программиста руки не кривые), то все будет работать правильно. Наследование это указание компилятору что некая часть различных структур памяти (то что мы называем объектом) имеет одинаковую организацию и с ней можно работать одинаково. Благодаря этому указанию С++ позволяет снять заботу с программиста по приведению указателей. Добавлено через 3 минуты и 14 секунд Кстати Ваш вопрос (о выборе метода) к наследованию прямого отношения не имеет. Это определяется правилами видимости. |
||||
|
|||||
| mes |
|
||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
а понял с какой стороны не хватало обзора..
вот два примерчика, в обоих один и тот же принцип :
и главное нужно понимать, что в примерах НЕТ ни одной функции с именем f(); Мы используем лишь часть имени, потому как о другой части компилятор может сам догадаться.. реально функция называется N::f() (где N специализация имени).. Т.е область определения входит в состав полного имени. Так что компилятор выбирает не какой адрес подставить, а какую специализацию несет имя. (т.е фактически опр. какое полное имя функции) Это сообщение отредактировал(а) mes - 14.1.2010, 17:51 |
||||
|
|||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Как всегда все оказалось сложнее, чем я думал
Вывод по теме: если у класса 1 или несколько родителей, то компилятор: 1. не создает копии методов родителей; 2. не располагает методы родителей и наследника в памяти друг за другом -> возможность преобразования указателя с наследника на его родителя обеспечивается... линковщиком? |
|||
|
||||
| baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
Более того, любая функция существует лишь в одном экземпляре. Помимо соображений достаточности есть еще одно простое: если используется указатель на функцию, то он должен быть одинаковым во всех частях программы. Значит и функция одна. При открытом наследовании родительские открытые функции становятся частью интерфейса потомка. Но не частью реализации. И вызов derived::f(), если f() унаследована из base, фактически означает base::f(), т.е. функция одна. mes все это подробно объяснил.
располагает как сочтет нужным, как именно - совершенно непринципиально. вообще-то компилятор этим занимается (в пределах единицы компиляции), но современные продвинутые линковщики тоже могут двигать. а преобразование типа линковщиком не осуществляется, это бред. в общем случае линковщик понятия не имеет о классах. адрес вызова определяет компилятор; в коде уже адрес конкретной функции. |
||||
|
|||||
| mes |
|
||||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
родители тут вобще не причем. Да и сами классы тоже. Важны понятия видимости/перекрытия имен ну и соответсвенно scope в котором располагается функция.
к памяти это отношения АБСЛЮТНО НЕ имеет, см пример с namespace важен не адрес функции, а ее Полное Специализированное Имя!
указатель тут НЕ причем !.. преобразование тоже НЕ причем !.. оно относится (в том смысле в каком Вы в этой теме подразумевали) только для доступа к данным. Для методов это "побочный эффект" - просто от типа указателя, зависит scope в котором компилятор начнет искать подходящее имя. т.е. если указатель типа B* то p->f() заменится на p->B::f(). когда делаете преобразование меняется и тип объекта к которому хотите применить операцию, ну и соответсвенно компилятор подставляет нужную специализацию. Это сообщение отредактировал(а) mes - 15.1.2010, 12:06 |
||||||
|
|||||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
||||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
нет.. Важно для выбора метода.. Вы рассматриваете преобразование и выбор подходящего метода как одну операцию , а их то две ! Добавлено @ 12:54 Чтоб не путаться дальше сформируйте вопросы заново, чтоб видно было, с чем Вы уже разобрались, а где ушли в сторону. Добавлено @ 13:05 Вот я вам составил пример, убрав все лишнее : методы, классы, наследование и т.д.
для начала разберитесь что происходит здесь, а потом уже легко расширите и на классы. Это сообщение отредактировал(а) mes - 15.1.2010, 13:05 |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
а также почему не работает, если изменить пример :
Это сообщение отредактировал(а) mes - 15.1.2010, 13:10 |
|||
|
||||
| Gunslinger |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Не знаю, что это -- char(). Вроде функция, но char -- ключевое слово, так использовать нельзя. Если это параметр char, то компилятор не поймет, т.к. в пространстве А функции с таким параметром нет.
Я уже запутался... Придется начать сначала. Что уже известно: 1. Данные класса группируют в памяти друг за другом ("блоковое" расположение) и у каждого объекта класса -- их своя копия. 2. Такие блоки связаны со своими методами скрытым параметром this (адресом на блок). 3. Методы класса (и простые функции) не группируются друг за другом и копий не имеют. Как? Добавлено через 3 минуты и 45 секунд
Не известно пространство имен. Это сообщение отредактировал(а) Gunslinger - 15.1.2010, 15:02 |
||||
|
|||||
| mes |
|
||||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
ну так запустите и проверьте..
данные-члены также бывают статические и нестатические. 1. статические объявляются в классе, но должны быть определены вне класса .. к объекту класса отношения не имеют. (для констант есть допуски которые не касаются этой темы ) 2. нестатические определяются внутри класса, и все вместе (вместе с нестатическими данными всех подобъектов) образуют общую (не смотря на то что описаны в разных классах) структуру объекта. Именно на эту структуру и указывает this в нестатических функциях-членах. Она же и определяет размер класса. ("структура" подразумевается не как ключевое слово stuct, a как понятие)
ну если связанны то точно также как и с другими аргументами. лучше сказать, что в функции-члены неявно передается параметр, который для нестатических функций доступен через ключевое слово this и указывает на адрес полученного объекта.
Что будет представлять в машинном коде функция(-член) мы сказать не можем. Она может быть заинлайнена, да так что от нее не останется и следа, а может состоять из целой череды асм-функций. Гарантируется одно, что адрес функции, где бы его не взяли, будет одним и тем же. Добавлено через 5 минут и 35 секунд угу.. точнее потому что подходящей функции с таким именем нет в области видимости. Это сообщение отредактировал(а) mes - 15.1.2010, 15:30 |
||||||
|
|||||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
mes, мне кажется, Вы даете топикстартеру ответы на вопросы, которые ему даже не приходят в голову. Представляю, какая уже каша из понятий видимости, наследования и проч...
Вообще мне кажется, стоит начать с того, что данные и код в памяти компьютера могут быть (и как правило находятся) в различных, удаленных друг от друга блоках памяти. Программист имеет дело с семантикой, описанной в стандарте, т.е. с некоей виртуальной машиной С++, а машинный код может получиться разным в зависимости от реализации компилятора. Есть наиболее популярные реализации, есть требования стандарта (типа последовательного расположения в памяти элементов vector), накладывающие ограничения на реализацию, но не более того. |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |