2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
|
|
1 | |
Вопрос по наследованию09.11.2011, 17:48. Показов 3539. Ответов 52
Метки нет (Все метки)
Уже неоднократно перечитывал главы про наследования и все равно до конца не разобрался.
Вот например у нас есть класс Четырехугольник, и мы создаем класс Прямоугольник. И в том и в другом классе есть функции Площадь и если у них будет одинаковая сигнатура, то вызовется функция того класса, объект которого мы создали. Если же сигнатуры совпадать не будут, то нужно явно указать с помощью оператора ::. Если мы сделаем функцию площади виртуальной, то при одинаковых сигнатурах вызовется функция своего класса. То же в случае разных сигнатур. То есть единственный плюс объявления функций виртуальными, это то что если мы создадим указатель на объект базового класса, он сможет указывать и на объект производного класса?
0
|
09.11.2011, 17:48 | |
Ответы с готовыми решениями:
52
Вопрос по наследованию вопрос по наследованию Вопрос по наследованию По наследованию |
ниначмуроФ
851 / 535 / 110
Регистрация: 12.10.2009
Сообщений: 1,913
|
|
10.11.2011, 08:29 | 21 |
конкретно по вопросу ramarren14
При объявлении функции виртуальной, компилятор выбирает функцию, удовлетворяющему тому, что занесено в указатель, а не типу указателя.
0
|
Заблокирован
|
|
10.11.2011, 08:44 | 22 |
0
|
1069 / 848 / 60
Регистрация: 30.04.2011
Сообщений: 1,659
|
|||||||||||
10.11.2011, 08:54 | 23 | ||||||||||
Лучше так не делать...
По поводу наследования и виртуальности. При наследовании (в С++ - только при открытом) работает принцип подстановки: на место объекта (указателя, ссылки) можно подставить объект производного класса. Обратно - нельзя. Наболее понятный пример: часы-будильник. Часы - базовый класс, будильник - наследник. Будильник является часами, но часы - не будильник. По поводу виртуальности - она без наследования совершенно бесполезна. А при наследовании полезна, например вот здесь:
Однако!
А если сделать ее виртуальной, то вызывается своя для каждого типа.
0
|
Делаю внезапно и красиво
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
|
|
10.11.2011, 09:05 | 25 |
Функция Call определена в Base. f не виртуальная, поэтому полиморфного вызова не будет.
0
|
1069 / 848 / 60
Регистрация: 30.04.2011
Сообщений: 1,659
|
|
10.11.2011, 09:16 | 26 |
0
|
Заблокирован
|
|
10.11.2011, 10:03 | 27 |
Этот ассерт не запрещает иметь прямоугольнику одинаковые примыкающее стороны! Не надо сочинять небылицы. Выражение внутри этого ассерта всегда равно Тру, внезависимости от того равны смежные стороны, или не равны. В выражении фигурирует только высота прямоугольника на момент начала работы функции и высота по завершению работы функции, ширины вобще там нет, она ни с чем не сравнивается. Равна она высоте или нет - вобще пофигу! Этот ассерт не запрещает иметь прямоугольнику однаковые прилегающие стороны как ты выразился... Смысл этого ассерта в том чтобы показать, что в прямоугольнике одна сторона может изменяться независимо от другой и при открытом наследовании данное свойство передастся и квадрату, что недопустимо!
Нет в примере Мейерса ничего дебильного, он же не виноват, что ты отрываешь книгу и видишь в ней фигу, а потом ещё и копируешь и тоже видишь при этом фигу. У меня уже слов нету, ты уже трижды пытался меня убедить в том, что этот ассерт запрещает иметь одинаковые смежные стороны прямоугольнику, что просто не соответсвует действительности! Или ты думаешь что если повторить ложь много раз, то она станет правдой или я в неё поверю? Нет. Если это какая то шутка, то я её не понял
0
|
0 / 0 / 0
Регистрация: 10.11.2011
Сообщений: 10
|
|
10.11.2011, 10:23 | 28 |
У мя аж глаз задергался, так что все таки вызывает A.Call
0
|
1069 / 848 / 60
Регистрация: 30.04.2011
Сообщений: 1,659
|
||||||
10.11.2011, 12:23 | 29 | |||||
Без виртуальности f() всегда вызывается функция базового класса.
С виртуальностью f() вызывается функция по типу объекта A. Аналогично с указателями:
0
|
0 / 0 / 0
Регистрация: 10.11.2011
Сообщений: 10
|
|
10.11.2011, 14:25 | 30 |
Объясните нубу зачем делать указатель на base, а затем засовывать в него адрес Derived.
0
|
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
|
|
10.11.2011, 15:02 | 31 |
bob2005, представьте, что у вас есть много разных геометрических фигур (квадраты, прямоугольники, круги и т.д.), все они наследники класса Shape. Пусть пользователь сам выбирает, сколько будет фигур, какие это будут фигуры и в каком порядке они создаются. Каждая фигура умеет себя рисовать (метод draw виртуальный). Фигура создаётся так: в массив указателей на Shape помещается адрес конкретной фигуры, только что созданной. И теперь, чтобы отрисовать все фигуры, нам просто-напросто надо пройтись по всему массиву shapes и для каждого элемента вызвать метод draw.
2
|
186 / 186 / 21
Регистрация: 08.01.2011
Сообщений: 1,139
|
||||||
10.11.2011, 17:15 | 32 | |||||
С указателями понятно. Без виртуальности будет вызываться метод класса Base, потому что тип указателя - Base.
Но не понятно, почему A.call() вызывает метод f() класса Base, если объект A имеет тип Derived, в котором метод f() переопределен. Вот пример, где вызывается именно метод класса Derived.
0
|
2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
|
|
10.11.2011, 17:47 [ТС] | 33 |
Ну так все верно. А если нужно, чтобы вызвался метод Base, надо A.Base::fun();
0
|
186 / 186 / 21
Регистрация: 08.01.2011
Сообщений: 1,139
|
|
10.11.2011, 18:11 | 34 |
0
|
Заблокирован
|
||||||
10.11.2011, 19:23 | 35 | |||||
А теперь смотрим код:
1. Почему Манипулятор принимает на входе ПРЯМОУГОЛЬНИК, но при этом запрещает быть ему квадратом? Квадрат, это что? Не прямоугольник что ли? 2. Почему Манипулятор таким грубейшим образом пытается вмешиваться во внутреннею работу объекта, и снаружи, игнорируя мнения объектов, за них решает, валидные они или нет? 3. Если вы на вход подадите объект "квадрат". Он у вас отработает. Абсолютно правильно. Так, как от него и ожидается. Но при этом все равно сработает ассерт. Так вот, почему ассерт заламывает абсолютно работоспособный процесс программы? Ну то есть, никакого сбоя нет в системе, а ассерт все равно всю программу аварийно тормознул. То есть этот сферический конь в вакууме - хорошая иллюстрация ущербной архитектуры. Хороший пример того, как делать не надо.
1
|
10.11.2011, 19:24 | 36 |
а ещё ели в базовом классе объявили функцию виртуальной то при наследовании она тоже будет виртуальной так что надобность явления в потомке виртуальной функции нужна лишь для того чтобы программисту было понятно что в базовом классе эта функция виртуальная
0
|
Делаю внезапно и красиво
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
|
|
10.11.2011, 19:35 | 37 |
Он не запрещает ему быть квадратом. Он запрещает изменять высоту при изменении ширины. У квадрата нет ширины и высоты, у него есть длина стороны, т.е. использовать метод задания ширины для квадрата не корректно. Вместо проверки рантайм типа объекта проверяется вот такое вот чудо.
Совершенно верно! Метод должен называться MakeWidthBigger и тогда он становится правильным. С данным названием он недоопределён и его поведение зависит от фактического типа объекта, что не есть хорошо.
0
|
Заблокирован
|
|
10.11.2011, 19:38 | 38 |
Тут нужно понимать одну вещь:
class Derived : public Base {} У класса Derived нет своего метода Call(); Этот метод есть только у Base Однако, после компиляции никаких Base уже не существует, как не существует и первоначального Derived . Существует неккий "результирующий" Derived . Который имеет метод Call() как свой собственный. Как будто бы он был прописан в Derived , а не в Base А вот если у Base и у Derived есть одноименные методы, то у результирующего Derived так же будут оба эти методы "как родные", но жить будут немножко по разным адресам. Тип данных Derived будит знать "где живёт метод родной для Derived" Тип данных Base будит знать "где живёт метод родной для Base " Я ж ссылочку кидал, где расписан "низкоуровневый взгляд на полиморфизм". Там это все очень подробно расжовано. Добавлено через 1 минуту Вот понимаете, вы сами это только сказали. вдумайтесь ещё раз в эти слова. Это все равно что сказать: "Я не запрещаю тебе быть квадратом, но если ты реально окажется квадратом, то я заломаю нафег всю программу"
1
|
Делаю внезапно и красиво
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
|
||||||
10.11.2011, 19:47 | 39 | |||||
Да, именно это я и сказал. Квадратом быть не запрещено. Запрещено изменять высоту при изменении ширины.
Ведь согласись, что следующая реализация метода не может быть у квадрата
К сожалению, там расписано для DecCpp (или что там было), но реализация полиморфизма никак не регламентирована и разработчики компиляторов вольны реализовывать его как им вздумается. Поэтому о "низкоуровневой" реализации лучше даже и не задумываться. Только если с привязкой к компилятору.
0
|
Заблокирован
|
|
10.11.2011, 20:27 | 40 |
в манипуляторе ничто не запрещает передавать ему прямоугольники и квадраты, он всегда отрабатывает до конца и ассерт никогда не срабатывает. Что ты подразумеваешь в таком случае под "запрещает" не понятно
Переключаем версию на релиз и нет никаких ассертов, что мы получаем? Квадрат стороны которого не равны друг другу, это в какой конторе такой код называется работоспобным? ну мне уже нечего добавить, я прочитал, осознал и полностью разделяю мнение мейерса насчёт данной проблемы, ну а ты можешь продолжать спорить тут и утверждать что мейерс баран, а также автор этой статьи http://www.objectmentor.com/re... es/lsp.pdf и все авторы которые я найду по запросу "square inherit rectangle" тоже бараны и ничего не шарят в ООП. Для меня мнение этих людей как то повесомее будет, чем мнение человека который с четвёртой попытки разобрался в листинге из 5 строк, потому что их точка зрения полностью аргументированна, а у твоей аргументации вобще нет
0
|
10.11.2011, 20:27 | |
10.11.2011, 20:27 | |
Помогаю со студенческими работами здесь
40
Непонятка по наследованию Вопросы по наследованию Работа в Eclipse по наследованию Задачка по наследованию классов Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |