![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Gunslinger |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Видимо для оптимизации, методы для всех объектов одного класса создаются в единственном экземпляре. А как при множественном наследовании? Методы всех наследуемых классов компилятор организовывает в один последовательный блок памяти или нет?
Например, псевдокод:
В памяти будет вроде:
И вариант, когда в коде создаем не только объект-наследник, но и объекты классов А и В. Это сообщение отредактировал(а) Gunslinger - 11.1.2010, 17:29 |
||||
|
|||||
| xvr |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
С точки зрения расположения в памяти методы класса ничем не отличаются от обычных функций. И в памяти они будут лежать как обычные функции. С переменными класса эта память никак не пересекается.
|
|||
|
||||
| mes |
|
||||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
нет, методы (функции члены) описываются внутри класса фактически только для задания области видимости в отличие от дата-членов.
фактически :
Это сообщение отредактировал(а) mes - 11.1.2010, 18:56 |
||||||
|
|||||||
| EnergoHokum |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 600 Регистрация: 10.11.2006 Где: Россия, Ставропол ь Репутация: нет Всего: 6 |
Здесь неплохо расписано, как выглядит наследование C++ на низком уровне.
|
|||
|
||||
| Gunslinger |
|
||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
EnergoHokum, ок.
Из статьи: "При наследовании в результирующем классе объединяются только члены с данными! Все методы существуют в единственном экземпляре." Я так понял, что компилятор для кода
создаст не
а... "распылит", что ли, по памяти.
Есть ли вообще прикладной смысл в этом знании? Какая-то мысль с приведениями указателей крутится. |
||||||
|
|||||||
| zim22 |
|
|||
|
depict1 ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2682 Регистрация: 15.1.2009 Где: Украина Репутация: 24 Всего: 69 |
почитай Lippman. Inside the C++ Object Model я думаю там будет ответ на твой вопрос |
|||
|
||||
| mes |
|
||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
по какой памяти ?
и
размещаются в памяти одинаково, только не в той памяти которую Вы судя по всему, имели ввиду. Это сообщение отредактировал(а) mes - 13.1.2010, 12:29 |
||||
|
|||||
| Gunslinger |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Нашел Липпмана, которого ты в прошлой теме советовал, но по отзывам в переводе неточности, а в коде встречаются ошибки. Так что я не рискнул. Эту книгу только на торрентсе нашел, пока не скачал. Тогда в адресном пространстве?
ps. Возможны синтаксические неточности. Это сообщение отредактировал(а) Gunslinger - 14.1.2010, 13:13 |
||||
|
|||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
Ваш пример не понял.. можете объяснить, как создание объекта связано с расположением функций(-членов)? |
|||
|
||||
| zim22 |
|
|||
|
depict1 ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2682 Регистрация: 15.1.2009 Где: Украина Репутация: 24 Всего: 69 |
||||
|
||||
| Gunslinger |
|
||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Тогда сегодня скачаю, заодно и по объектной модели.
Попробую... Вот мои мысли: 1. Приведение указателя -- адрес остается тем же, только меняется тип. Т.е. указывал на участок памяти одного размера (начиная с какого-то адреса), теперь указывает на участок памяти другого размера (при этом, начиная с того же самого адреса). 2. Наследование С: public A, pubic B, ... . Методы классов родителей и наследника объединяются и располагаются в памяти друг за другом, в порядке списка наследования -- сначала А, затем В и С. Таким образом с помощью указателя можно получать доступ к методам не только наследника, но и всех его родителей, перемещаясь по этой области памяти. То есть тот же самый код:
|
||||||
|
|||||||
| xvr |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Методы - это ОБЫЧНЫЕ функции с неявным дополнительным формальным параметром. |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Я не писал о данных. При чем здесь они? Я уже знаю, что они лежат отдельно, а у методов есть this на них.
Вот это я и хочу понять. Получается, например, так: есть 2 класса и есть класс 3 - их наследник. Копию родителей не создает, понятно. А как располагает в адресном пространстве? Друг за другом или нет? |
|||
|
||||
| mes |
|
||||||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
зря Вы перешли к множественному наследованию не разобравшись с классическим. При множественном наследовании это не так. Адрес меняется.
Какое отношение расположение методов имеет к указателю this ? какой бы ни был this методы всегда продолжают лежать на своем месте, и
Кажись я понял в чем дело.. Вас сбила терминология. Есть два разных добирания... Когда речь идет о добирании до методов, роль играет не значение указателя (оно может бытэ любым хоть NULL), а его тип. И второе добирание, когда функция-член посредством this хочет добраться до данных. В примере ниже мы не используем ни виртуальных ни данных объекта, поэтому смело можем передавать NULL в качестве аргумента. (но не забываем что пример тестовый и в реале подобный подход не рекомендуется) И в зависимости от приведения у нас выберется нужная функция.
|
||||||||
|
|||||||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
||||
|
||||
| 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), накладывающие ограничения на реализацию, но не более того. |
|||
|
||||
| Gunslinger |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Хм, не видит char(). Выводит int. Уточнение: полученный объект == копия данных класса? (Раньше объект воспринимал монолитно: объект - это и данные, и методы(когда не знал, что методы существуют в одном экземпляре))
Это? Это сообщение отредактировал(а) Gunslinger - 15.1.2010, 17:29 |
||||
|
|||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
не чар не видит.. когда нет абсолютно подходящей функции, тогда происходит неявное преобразование параметров. но это как правильно заметил baldina будет лишним.. оставим разбор на будущее.. зависит от способа передачи: если по значению то копия если по имени/ссылке то оригинал уточнение объект (инстанция класса) это совокупность всех не статических данных-членов как самого класса, так и всех его подклассов (и некой служебной информации в случае обладания виртуальными функциями) это про статические данные корректно говорить что они существуют в единственном экземпляре. а когда такое про функции - то слух режет. Дело в том смысле какой Вы вкладываете. Не важно в вашем вопросе сколько экземпляров метода существует. А в том что функции не принадлежат обьекту, а оперируют им.
мы вызвали НЕ функцию f объекта obj, а вызвали функцию f класса A и передали ей объект obj как параметр. ( то что получит функция зависит от способа передачи.. то есть прежде чем стать аргументом this может произойти как простое копирование (при передаче по значению), так и преобразование типа .. но это опять другая тема) Это сообщение отредактировал(а) mes - 15.1.2010, 20:00 |
|||
|
||||
| Gunslinger |
|
||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Это я понимаю. Просто хотел подчеркнуть, что:
Компилятор создает:
Это сообщение отредактировал(а) Gunslinger - 15.1.2010, 21:46 |
||||||
|
|||||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
у Вас либо куча опечаток в коде, либо Вы все таки не до конца поняли... |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
||||
|
||||
| mes |
|
||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
ну прежде всего в первом коде идет создание N объектов, а во 2м описание N структур объектов.
ну и мелочь : аналог метода описанный в namespace должен принимать (скрытый) параметр на объект. Вот расширенный пример того что Вы писали:
может быть представлен в таком условном коде : /* примечания : в квадратных скобках указываются скрытые параметры (при чтение кода не учитывать так как не являются разделительными) со знаком $ обозначены внутренние действия компилятора указание прав доступа не учитывается.. код не отнсящийся на прямую к примеру (std::cout) представлен без изменений */
надеюсь пример не запутает Вас eще сильней.. старался сделать как можно понятнее.. Это сообщение отредактировал(а) mes - 19.1.2010, 20:08 |
||||
|
|||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
||||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
Вы ж не думаете, что принятая форма записи в С++ - единственная возможная ? часть B повторяет структуру А ? есть правило приведения от наследника к базовому ? Ну значит условно наследуется. ;) Я специально выбрал вариант, чтоб на разнице показать что есть наследование по сути. А вообще компилятор прежде, чем компилить в объектный файл, приводит текст программы в удобное для него состояние. Rаньше С++ компилятор был вообще простым С-кодогенератором. Т.е. из С++ программы генерил С-код (в котором как известно нет инструмента наследования). Ну так будем считать, что приведенный пример одна из стадий (препроцессор) такого кодогенератора, которая разворачивает код связанный с наследованием в условный с-структурный вид. Это сообщение отредактировал(а) mes - 18.1.2010, 11:28 |
|||
|
||||
| Gunslinger |
|
||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Кроме с++ной записи о других не знаю. Т.е. вы описали то же наследование? А то у меня чуть крыша не поехала
char [A::] c; -- это вроде ссылки или указателя на структуру А? Как происходит подобное приведение: определяется, где в структуре В находится А::с? |
||||||
|
|||||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
Будет точнее сказать что я раскрыл классы с наследованием на простые структуры с той же зависимостью.
нет.. Зачем определяться если структура наследник, содержит все данные предка в той же последовательности с нулевым (в нашем случае) смещением. |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
static_cast - это безопасное приведение. Для того чтоб наш наследник мог конвертиться мы установили хотя на самом деле лучше подошла бы функция-конвертер, но это опять уже несколько другая тема.. |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Благодаря скрытому параметру this каждый метод определяет, где находятся данные, с которыми он будет работать.. Тогда такое приведение значит, что this B меняется на this, где расположена struct A? Это сообщение отредактировал(а) Gunslinger - 19.1.2010, 12:50 |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
убрал я из примера static_cast - для сути он не нужен. имя "A::f" логически идеентично "A_f", а "::" просто специфичный разделитель, позволяющий программисту записывать имена в неполной форме. (до полной дорабатывает компилятор) Хотя приведенное еще не полное имя функции, а специализированное.. - т.е. в имя включена зона в которой его определили. полное включает в себя еще типы параметров, благодаря чему и становится возможна перегрузка. |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Например, из кода
Компилятор делает нечто вроде A_char_c? Т.е. это то, как «выглядит» переменная на, практически, самом нижнем уровне? Еще одна вещь, над которой я раньше не задумывался.. Это сообщение отредактировал(а) Gunslinger - 20.2.2010, 15:01 |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
ага, в принципе так, только в более удобном для него виде. И с функциями тоже самое. Добавлено через 3 минуты и 4 секунды
1. не переменная, а ее имя. 2. на самом низшем имя заменяется на значения (например смещения), поэтому не на самом низшем, а после раскрытия всех скоупов (пространств имен) |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Таким образом компилятор реализует и различные ограничители, вроде private, protected, namespace, const -- всего лишь добавляет к имени переменной\метода соответствующие "пометки"? Это сообщение отредактировал(а) Gunslinger - 20.2.2010, 17:55 |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
Ага, определение характеристик сущности в любом нужно-произвольном месте основывается на "пометках", которые компилятор запоминает для каждой сущности в процессе парсинга кода. Единственное, что не все пометки отражаются на имени. Полное имя нужно линкеру для связки - и на тот момент уже нет ни типов, ни скоупов, есть только имя. Компилятору необходимо гораздо больше информации (например тип, размер, право доступа), поэтому все "пометки" он хранит в специальных внутренних структурах. Как именно он хранит, каждый компилятор решает сам. |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
static переменные\методы, например? Существуют ведь в одной копии -- линкер вроде запутаться не должен. По поводу Вашего предыдущего примера кода.
b.A::f() -- вроде вызывается для объекта b, но у метода адрес на данные объекта а. Получается, f() возьмет не переменную "c" наследника, родителя: а.с? |
|||
|
||||
| mes |
|
||||||||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
про запутаться :
какую f вызвать из этих линкеру было бы не понятно, поэтому для него обоим функциям задается вид типа например такого :
где в нашем случае для разделителя выбрано число показывающее кол-во символов до следующего разделителя. второй вариант, экспортировать имя функции в стиле, тогда у функции будет "нормальное" имя, но такая функция лишиться возможности перегрузки и расположения не в глобальном пространстве имен. В общем это уже в сторону от темы, и для разбора для начала почитать что такое mangling имен, и с чем его едят.
по адресу b есть данные как наследника , так и родителя,
да, так как мы указали явно что надо использовать функцию A::f будет вызвана именно она, а соответсвенно использоваться будет дата_член A::c. |
||||||||||
|
|||||||||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
В b есть копия переменной-родителя, однако ни метод b.f(), ни b.a::f() не могут к ней обратиться: либо к b.c, либо к a.c. Как же тогда обратиться к [A::]с в наследнике? Знаю только, как в ActionScript3 такое сделано, но там все просто: super.наследованная_переменная. |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
а в паскaле есть служебное слово inherited, ну а в С++ никаких служебных слов для этого не надо, достаточно указать специализированное имя переменной.
Это сообщение отредактировал(а) mes - 21.2.2010, 11:05 |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
||||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
ну так в самом начале же разбирали, что объект включает в себя все дата-члены как своего класса, так и всех предков. то есть объект класса B имеет следующие дата-члены :
так как с именем i две переменных, то имя определенное в наследнике скрывает имя определенное в предке, поэтому если необходимо обратиться к последнему, то необходимо уточнение (специализация имени). Ну а если например Вы б обратились например к переменной x, то так как их нет в описании класса и его предков, то компилятор предположил бы что обращаетесь к "наружней" (не к члену) переменной и начал бы искать подходящую там. Пример из жизни. Допустим Вы студент, и в Вашем классе есть Коля. Когда Вы говорите о нем со своими однокурсниками, то всем понятно о ком речь. Но на параллельном курсе тоже есть Коля, и когда Вы хотите упомянуть его, то должны уточнить о ком именно идет речь. А вот например парень с именем Аквакате только один на весь институт, и ни у кого сомнения не возникнет о ком идет речь, даже не уточняя. В общем язык программирования это тоже язык, и если в ЯНУ все плоско и каждая конструкция имеет только одно соответствие, то ЯВУ позволяет себе "такую же" игру слов как и разговорные язык и смысл конструкции не очевиден без знания контекста. для Си обычно приводят пример : что есть i * j ?; |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Так ведь включает "копию", а не оригинал. Оригинал как принадлежал родителю, так и принадлежит... Вначале темы думал, что при наследовании создаются и копии методов, которые "перенаправляются" на унаследованные дата-члены. Оказалось ошибался -- копии методов не создаются и не "перенаправляются", а продолжают указывать на дата-члены родителя. Но теперь куча других вопросов: 1. Как обратиться к унаследованным переменным? 2. Если в родителе реализовывался какой-нибудь механизм (методы выполняли и писали состояние в дата-члены), то, если в наследнике предварительно не выполнить эти механизмы, то можно поломать логику работы наследника.. Как тогда быть, методы родителя же "направлены" на дата-члены родителя? |
|||
|
||||
| mes |
|
||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
Ну вот приехали.. разберем на примере из жизни : Млекопитающего, как базового класса и волка как наследника.
Мы имеем два описания, притом второе включает в себя первое по принципу наследования. Фактически это говорит, что все что справедливо для объекта второго описания действительно и все что описано в первом. Описание и есть класс, при том первое описание - абстрактный класс, так как по нему не понятно какой именно объект имеется ввиду, и обладает недостаточной информацией для "построения" объекта данного класса второе описание - конкретный класс, так как обладает достаточной информацией для "построения" объекта данного класса. А вот и сам обьект, изображен на картинке : ![]() Как видно этому объекту соответствуют оба описания. В программировании говорится, что поддерживает оба интерфейса, что другими словами означает, что поведение объекта справедливо для обоих описаний. Также очевидно, что описаний может быть намного больше. Теперь хотелось бы уточнить сказанное в Вашей цитате, копии чего из класса содержит объект ?! Это сообщение отредактировал(а) mes - 23.2.2010, 13:22 |
||||
|
|||||
| mes |
|
||||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
вот Вам еще один пример
Добавлено через 4 минуты и 30 секунд теперь построчный перевод вышеприведенного примера, но все методы заменены на обычные функции.
Добавлено через 10 минут и 1 секунду теперь тот же пример при отсутствии в языке механизма наследования
за соответсвие передаваемых типов отвечает не компилятор, а программист. Это сообщение отредактировал(а) mes - 23.2.2010, 11:58 |
||||||
|
|||||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
опять тот же пример, но с отсутствием в языке механизма стуктур
Добавлено @ 12:17 думаю примеров Вам хватит, и в них вроде бы отражены вплоть до низшего уровня все вопросы этой темы. Это сообщение отредактировал(а) mes - 23.2.2010, 13:19 |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Большое спасибо за терпеливое разъяснение и за пример с отсутствием структур -- очень доходчивый. Теперь понятно. Метод родителя можно "перенаправить" на унаследованные дата-члены -- это возможно за счет того, что в наследник добавляются сначала дата-члены родителя, а потом уже наследника. При такой последовательности методы родителя "знают" смещение "своих" унаследованных дата-членов. А как быть с множественным наследованием? Если class C: A, B, дата-члены В будут располагаться после дата-членов А, и тогда методы В будут "смотреть" не туда -- смещение будет неверным. Компилятор создает какой-нибудь дополнительный механизм? Это сообщение отредактировал(а) Gunslinger - 28.2.2010, 09:47 |
|||
|
||||
| mes |
|
||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
ура !
Это сообщение отредактировал(а) mes - 28.2.2010, 14:22 |
||||
|
|||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
вот Вам тогда еще один демонстрационный пример без структур, с учетом механизма множественного наследования.
P.S. в примере специально использовано двойное унаследование класса A классом AB () (прямое и косвенное посредством класса B), что делает пример не соответствующим правилам С++ из за появления неопределенностей преобразования (в нашем случае работает из за явного указания нужного преобразования), но имхо так лучше для понимания происходящего. Это сообщение отредактировал(а) mes - 28.2.2010, 15:44 |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |