Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 17, средняя оценка - 4.82
ramarren14
2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
#1

Вопрос по наследованию - C++

09.11.2011, 17:48. Просмотров 2173. Ответов 52
Метки нет (Все метки)

Уже неоднократно перечитывал главы про наследования и все равно до конца не разобрался.
Вот например у нас есть класс Четырехугольник, и мы создаем класс Прямоугольник.
И в том и в другом классе есть функции Площадь и если у них будет одинаковая сигнатура, то вызовется функция того класса, объект которого мы создали. Если же сигнатуры совпадать не будут, то нужно явно указать с помощью оператора ::.
Если мы сделаем функцию площади виртуальной, то при одинаковых сигнатурах вызовется функция своего класса. То же в случае разных сигнатур. То есть единственный плюс объявления функций виртуальными, это то что если мы создадим указатель на объект базового класса, он сможет указывать и на объект производного класса?
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.11.2011, 17:48
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Вопрос по наследованию (C++):

Вопрос по наследованию - C++
Вопрос насчёт передачи аргументов в конструктор базового класса(создания временного объекта), а именно почему у меня это не выходит и где у...

Вопросы по наследованию - C++
Вопрос ещё по конструкторам Допустим есть система классов class A { public: A() {} }; class B: public A {

Задание по наследованию классов - C++
Создать иерархию классов : линия - прямоугольник - пирамида. Все классы должны содержать методы для фиксации и получения значений всех...

Задача по наследованию в C++, нужно реализовать некоторые моменты - C++
Написать программу с объектами и реализовать наследование. Ситуация: Klimat (базовый объект), Derevo (выводной объект). a. Klimat:...

Задача по наследованию. Не понимаю некоторые моменты в формулировке задания - C++
Здравствуйте! Вот есть задание: Описать базовый класс СТРОКА Обязательные поля класса: # Указатель на char - хранит адрес...

"Предпочитайте композицию наследованию" - C++
Привет. В книге "Стандарты программирования на С++" есть совет 34: "Предпочитайте композицию наследованию" Хочу уточнить на счет...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
10.11.2011, 15:02 #31
bob2005, представьте, что у вас есть много разных геометрических фигур (квадраты, прямоугольники, круги и т.д.), все они наследники класса Shape. Пусть пользователь сам выбирает, сколько будет фигур, какие это будут фигуры и в каком порядке они создаются. Каждая фигура умеет себя рисовать (метод draw виртуальный). Фигура создаётся так: в массив указателей на Shape помещается адрес конкретной фигуры, только что созданной. И теперь, чтобы отрисовать все фигуры, нам просто-напросто надо пройтись по всему массиву shapes и для каждого элемента вызвать метод draw.
2
Chelioss
180 / 180 / 4
Регистрация: 08.01.2011
Сообщений: 1,133
10.11.2011, 17:15 #32
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
Без виртуальности f() всегда вызывается функция базового класса.
С виртуальностью f() вызывается функция по типу объекта A.
Аналогично с указателями:
C++
1
2
3
4
Base *p;
Derived A;
p = &A;
p->Call();
При виртуальности вызовется f() наследника, без виртуальности - f() базовая
С указателями понятно. Без виртуальности будет вызываться метод класса Base, потому что тип указателя - Base.
Но не понятно, почему A.call() вызывает метод f() класса Base, если объект A имеет тип Derived, в котором метод f() переопределен.
Вот пример, где вызывается именно метод класса Derived.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
 
class Base
{
public: void f(){ std::cout << "Base\n"; }
};
class Derived: public Base
{
public: void f(){ std::cout << "Derived\n"; }
};
 
int main()
{
    Derived A;
    A.f();
    system( "pause" );
    return 0;
}
?
0
ramarren14
2 / 2 / 0
Регистрация: 14.07.2011
Сообщений: 49
10.11.2011, 17:47  [ТС] #33
Ну так все верно. А если нужно, чтобы вызвался метод Base, надо A.Base::fun();
0
Chelioss
180 / 180 / 4
Регистрация: 08.01.2011
Сообщений: 1,133
10.11.2011, 18:11 #34
Цитата Сообщение от ramarren14 Посмотреть сообщение
Ну так все верно. А если нужно, чтобы вызвался метод Base, надо A.Base::fun();
Ну не где такое не писали, но все равно вызвался метод класса Base.
0
Bers
Заблокирован
10.11.2011, 19:23 #35
Цитата Сообщение от LosAngeles Посмотреть сообщение
Не надо сочинять небылицы. Выражение внутри этого ассерта всегда равно Тру, внезависимости от того равны смежные стороны, или не равны. В выражении фигурирует только высота прямоугольника на момент начала работы функции и высота по завершению работы функции, ширины вобще там нет, она ни с чем не сравнивается. Равна она высоте или нет - вобще пофигу! Этот ассерт не запрещает иметь прямоугольнику однаковые прилегающие стороны как ты выразился... Смысл этого ассерта в том чтобы показать, что в прямоугольнике одна сторона может изменяться независимо от другой и при открытом наследовании данное свойство передастся и квадрату, что недопустимо!

А теперь смотрим код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void makeBigger(rectange& r)
{
int old = r.height();    //пофиксили высоту 
          //пока ещё валидного прямоугольника
 
r.setWidth( r.width()+10);  //единственный метод, 
                       //который может привести данные 
                                //в "не_валидное состояние"
 
//для прямоугольника метод изменит ширину.
//для квадрата изменит и ширину, и высоту.
 
assert( r.height() == old ); //что здесь проверяется?
 
//По мнению данной функции-манипулятора
//Если у прямоугольника высота изменилась в результате 
//работы методы setWidth() 
//то считать, что была выполнена недопустимая операция
//И поднять тревогу
 
//Какое утверждение заложено в ассерт?
//"при изменении ширины прямоугольника,
//Его высота должна остаться прежней"
 
}
Вопросы:

1. Почему Манипулятор принимает на входе ПРЯМОУГОЛЬНИК, но при этом запрещает быть ему квадратом? Квадрат, это что? Не прямоугольник что ли?

2. Почему Манипулятор таким грубейшим образом пытается вмешиваться во внутреннею работу объекта, и снаружи, игнорируя мнения объектов, за них решает, валидные они или нет?

3. Если вы на вход подадите объект "квадрат". Он у вас отработает. Абсолютно правильно. Так, как от него и ожидается. Но при этом все равно сработает ассерт. Так вот, почему ассерт заламывает абсолютно работоспособный процесс программы?
Ну то есть, никакого сбоя нет в системе, а ассерт все равно всю программу аварийно тормознул.


То есть этот сферический конь в вакууме - хорошая иллюстрация ущербной архитектуры.
Хороший пример того, как делать не надо.
1
Van111
кодер с++
209 / 188 / 4
Регистрация: 03.08.2011
Сообщений: 2,597
Записей в блоге: 12
10.11.2011, 19:24 #36
Цитата Сообщение от ramarren14 Посмотреть сообщение
Уже неоднократно перечитывал главы про наследования и все равно до конца не разобрался.
Вот например у нас есть класс Четырехугольник, и мы создаем класс Прямоугольник.
И в том и в другом классе есть функции Площадь и если у них будет одинаковая сигнатура, то вызовется функция того класса, объект которого мы создали. Если же сигнатуры совпадать не будут, то нужно явно указать с помощью оператора ::.
Если мы сделаем функцию площади виртуальной, то при одинаковых сигнатурах вызовется функция своего класса. То же в случае разных сигнатур. То есть единственный плюс объявления функций виртуальными, это то что если мы создадим указатель на объект базового класса, он сможет указывать и на объект производного класса?
а ещё ели в базовом классе объявили функцию виртуальной то при наследовании она тоже будет виртуальной так что надобность явления в потомке виртуальной функции нужна лишь для того чтобы программисту было понятно что в базовом классе эта функция виртуальная
0
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
10.11.2011, 19:35 #37
Цитата Сообщение от Bers Посмотреть сообщение
Почему Манипулятор принимает на входе ПРЯМОУГОЛЬНИК, но при этом запрещает быть ему квадратом? Квадрат, это что? Не прямоугольник что ли?
Он не запрещает ему быть квадратом. Он запрещает изменять высоту при изменении ширины. У квадрата нет ширины и высоты, у него есть длина стороны, т.е. использовать метод задания ширины для квадрата не корректно. Вместо проверки рантайм типа объекта проверяется вот такое вот чудо.

Цитата Сообщение от Bers Посмотреть сообщение
Хороший пример того, как делать не надо.
Совершенно верно! Метод должен называться MakeWidthBigger и тогда он становится правильным. С данным названием он недоопределён и его поведение зависит от фактического типа объекта, что не есть хорошо.
0
Bers
Заблокирован
10.11.2011, 19:38 #38
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
Нет. Без виртуальности вызовется базовый...
Тут нужно понимать одну вещь:

class Derived : public Base {}

У класса Derived нет своего метода Call();
Этот метод есть только у Base

Однако, после компиляции никаких Base уже не существует, как не существует и первоначального Derived . Существует неккий "результирующий" Derived .
Который имеет метод Call() как свой собственный. Как будто бы он был прописан в Derived ,
а не в Base

А вот если у Base и у Derived есть одноименные методы, то у результирующего Derived так же будут оба эти методы "как родные", но жить будут немножко по разным адресам.
Тип данных Derived будит знать "где живёт метод родной для Derived"
Тип данных Base будит знать "где живёт метод родной для Base "

Я ж ссылочку кидал, где расписан "низкоуровневый взгляд на полиморфизм". Там это все очень подробно расжовано.

Добавлено через 1 минуту
Цитата Сообщение от Deviaphan Посмотреть сообщение
Он не запрещает ему быть квадратом. Он запрещает изменять высоту при изменении ширины.
Вот понимаете, вы сами это только сказали. вдумайтесь ещё раз в эти слова.

Это все равно что сказать: "Я не запрещаю тебе быть квадратом, но если ты реально окажется квадратом, то я заломаю нафег всю программу"
1
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
10.11.2011, 19:47 #39
Цитата Сообщение от Bers Посмотреть сообщение
Это все равно что сказать: "Я не запрещаю тебе быть квадратом, но если ты реально окажется квадратом, то я заломаю нафег всю программу"
Да, именно это я и сказал. Квадратом быть не запрещено. Запрещено изменять высоту при изменении ширины.
Ведь согласись, что следующая реализация метода не может быть у квадрата
C++
1
2
3
4
5
6
7
8
class Brick : public rectangle
{
      void setWidth( int w )
     {
          _width = w;
          _height = w*4;
     }
};
Добавлено через 5 минут
Цитата Сообщение от Bers Посмотреть сообщение
где расписан "низкоуровневый взгляд на полиморфизм". Там это все очень подробно расжовано.
К сожалению, там расписано для DecCpp (или что там было), но реализация полиморфизма никак не регламентирована и разработчики компиляторов вольны реализовывать его как им вздумается. Поэтому о "низкоуровневой" реализации лучше даже и не задумываться. Только если с привязкой к компилятору.
0
LosAngeles
Заблокирован
10.11.2011, 20:27 #40
Цитата Сообщение от Bers Посмотреть сообщение
1. Почему Манипулятор принимает на входе ПРЯМОУГОЛЬНИК, но при этом запрещает быть ему квадратом? Квадрат, это что? Не прямоугольник что ли?
в манипуляторе ничто не запрещает передавать ему прямоугольники и квадраты, он всегда отрабатывает до конца и ассерт никогда не срабатывает. Что ты подразумеваешь в таком случае под "запрещает" не понятно

Цитата Сообщение от Bers Посмотреть сообщение
3. Если вы на вход подадите объект "квадрат". Он у вас отработает. Абсолютно правильно. Так, как от него и ожидается. Но при этом все равно сработает ассерт. Так вот, почему ассерт заламывает абсолютно работоспособный процесс программы?
Переключаем версию на релиз и нет никаких ассертов, что мы получаем? Квадрат стороны которого не равны друг другу, это в какой конторе такой код называется работоспобным?

Цитата Сообщение от Bers Посмотреть сообщение
То есть этот сферический конь в вакууме - хорошая иллюстрация ущербной архитектуры.
Хороший пример того, как делать не надо.
ну мне уже нечего добавить, я прочитал, осознал и полностью разделяю мнение мейерса насчёт данной проблемы, ну а ты можешь продолжать спорить тут и утверждать что мейерс баран, а также автор этой статьи http://www.objectmentor.com/resources/articles/lsp.pdf и все авторы которые я найду по запросу "square inherit rectangle" тоже бараны и ничего не шарят в ООП. Для меня мнение этих людей как то повесомее будет, чем мнение человека который с четвёртой попытки разобрался в листинге из 5 строк, потому что их точка зрения полностью аргументированна, а у твоей аргументации вобще нет
0
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
10.11.2011, 20:30 #41
Цитата Сообщение от LosAngeles Посмотреть сообщение
Переключаем версию на релиз и нет никаких ассертов, что мы получаем?
Как бы игнорирование ошибки не есть её исправление...
Отключать ассерты в релизе не есть хорошо. Стандартный ассерт УГ, сакс и фтопку.
0
Bers
Заблокирован
10.11.2011, 20:35 #42
Цитата Сообщение от Deviaphan Посмотреть сообщение
Ведь согласись, что следующая реализация метода не может быть у квадрата
Да, не может. Поэтому, квадрат можно отнаследовать от прямоугольника, но нельзя отнаследовать от кирпича.

Если ваш манипулятор ожидает на входе кирпич, то он и должен принимать только кирпичи, а не все мыслимые и не мыслимые прямоугольники.

Если манипулятор ожидает на входе все мыслимые и не мыслимые прямоугольники, то он должен быть готов к тому, что придти может и кирпич, и квадрат.

Если манипулятор не делает различий между кирпичом и квадратом, но в рантайме ломает все квадраты - это архитектурный фейл.

Проектирование по принципу: "Я не запрещаю тебе быть квадратом, но если ты реально окажется квадратом, то я заломаю нафег всю программу"

Это проектирование по принципу: "Здесь, здесь и здесь я закопаю мину. Специально, что бы взрывать полностью работоспособный процесс".

Добавлено через 2 минуты
Цитата Сообщение от LosAngeles Посмотреть сообщение
Переключаем версию на релиз и нет никаких ассертов, что мы получаем?
Кашу в голове, и мину замедленного действия в коде мы получаем. И программиста, который не вполне себе осознает, для чего вообще существуют ассерты
1
Le Thaw
10.11.2011, 20:37
  #43

Не по теме:

Bers, зачетные цитаты.

0
LosAngeles
Заблокирован
10.11.2011, 20:39 #44
Цитата Сообщение от Deviaphan Посмотреть сообщение
Совершенно верно! Метод должен называться MakeWidthBigger и тогда он становится правильным. С данным названием он недоопределён и его поведение зависит от фактического типа объекта, что не есть хорошо.
нет, от изменения названия он правильнее не станет ни на йоту. Я вправе ожидать от квадрата, что его стороны будут равны друг другу в любой момент времени, а не подбирать функцию исходя из её названия(что за лол?) и гадать, а не приведёт ли она квадрат в противоречивое состояние, что в случае наследования от прямоугольника сделать легко. Так что если найдётся хоть один способ привести квадрат в противоречивое состояние через его же интерфейс, значит вся иерархия тухлая.
0
Bers
Заблокирован
10.11.2011, 20:41 #45
Цитата Сообщение от Deviaphan Посмотреть сообщение
но реализация полиморфизма никак не регламентирована и разработчики компиляторов вольны реализовывать его как им вздумается. Поэтому о "низкоуровневой" реализации лучше даже и не задумываться. Только если с привязкой к компилятору.
Ну как бы, на самом деле и не нужно об этом задумываться. Нужно просто понимать, как он должен работать.

Главный принцип: указатель базового типа запустит метод потомка, если сам указатель будит указывать на этого потомка, а сам метод будит виртуальным.

Если метод будит не виртуальным, запустится базовый метод.

По моему, вполне достаточно для понимания)
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.11.2011, 20:41
Привет! Вот еще темы с ответами:

Написать простейшую программу по "перегрузке" и "наследованию" - C++
написать простейшую программу на СИ++ по &quot;перегрузке&quot; и &quot;наследованию&quot;. заранее спасибо!

Вопрос по массивав, "институтский" вопрос. - C++
Готовлюсь к летней сессии по программированию. С++ Есть такая вот задачка (привожу как есть) В документации подобного не...

Вопрос по наследованию - C#
Вывод Hello СHild Hello Base Что сделать чтобы Base не выводило при подобном вызове? using System; namespace...

вопрос по наследованию - PHP ООП
начал изучать ООП в РНР. нужно уточнение. имеется класс статей Aticle и дочерний класс NewsArticle, они отличаются тем что у второго...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
10.11.2011, 20:41
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru