Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.64/11: Рейтинг темы: голосов - 11, средняя оценка - 4.64
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231

Наследование

19.08.2020, 15:16. Показов 2425. Ответов 33

Студворк — интернет-сервис помощи студентам
Потихоньку изучаю С++. Разбираю реализацию ООП на этом языке.
Сделал простенькие класса для понимания концепции наследования.

Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person
{
protected:
    std::string _name;
    unsigned int _age;
 
public:
    Person(std::string name, unsigned int age ) : _name{name}, _age{age} {}
    virtual ~Person() = default;
 
    virtual void print() { std::cout << _name << _age << std::endl; }
};
 
class Professor : public Person
{
public:
    Professor(std::string name, unsigned int age) : Person{ name, age } {}
    virtual ~Professor() = default;
 
    void print() override { std::cout << "Prof " << _name << " " << _age << std::endl; }
};


Решил добавить к этому контейнеры. Создал ещё два класса.

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class House
{
public:
    virtual ~House() = default;
 
    virtual std::vector<Person*> get_person() { throw new std::exception("NotImplemented"); };
};
 
class University : public House
{
private:
    std::vector<Professor*> _professors;
public:
 
    std::vector<Person*> get_person() override{ return _professors; };
 
};

И тут началось. Не работает метод get_person() класса University. Не понимаю почему. dynamic_cast не помогает. Правда, я мб неправильно его использую? Делаю так
C++
1
dynamic_cast<std::vector<Person*>>(_professors)
. Что я делаю неправильно?
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
19.08.2020, 15:16
Ответы с готовыми решениями:

Заменить наследование классов на наследование интерфейсов
#include &lt;iostream&gt; #include &lt;assert.h&gt; using namespace std; int people_on_base = 100; int vehicles_on_base = 100; double...

Наследование
Наследование 1)Должна быть табличка 3*3 2)Разные типы наследования 3)программа в в которой будет наследоваться клас 4) наследуются...

С++ Наследование
#include &lt;conio.h&gt; #include &lt;iostream.h&gt; class MyClass { int a; public: MyClass(int); show_a(int) ...

33
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
19.08.2020, 16:02
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Не понимаю почему. dynamic_cast не помогает. Правда, я мб неправильно его использую? Делаю так
Потому что std::vector не полиморфный тип.
Полиморфные у вас только Person <- Professor.

PS
___________
Цитата Сообщение от schoolboy_ Посмотреть сообщение
throw new std::exception("NotImplemented");
Не делайте так. Это не C#.

>
C++
1
throw std::exception("NotImplemented");
1
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 16:03  [ТС]
Но если сделать так, то всё работает.
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class University : public House
{
private:
    std::vector<Person*> _professors;
public:
 
    void add_professor(Professor* professor) { _professors.push_back(professor); }
    std::vector<Person*> get_persons() override { return _professors; };
 
    void print()
    {
        for (auto professor : _professors)
            professor->print();
    }
 
};


но не работает такой код:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
Person* p = new Person("Oleg", 18);
Person* prof = new Professor("Bjarne Stroustrup", 54);
 
University u;
u.add_professor(p);
u.add_professor(prof);


Цитата Сообщение от DrOffset Посмотреть сообщение
Не делайте так.
почему?

Цитата Сообщение от DrOffset Посмотреть сообщение
Потому что std::vector не полиморфный тип.
Полиморфные у вас только Person <- Professor.
Как мне вернуть коллекцию элементов базового класса?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
19.08.2020, 16:09
Лучший ответ Сообщение было отмечено schoolboy_ как решение

Решение

Цитата Сообщение от schoolboy_ Посмотреть сообщение
почему?
Потому что делаете утечку памяти.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Как мне вернуть коллекцию элементов базового класса?
Скопировать - больше никак.

C++
1
2
3
std::vector<Person*> get_person() override { 
    return std::vector<Person *>(_professors.begin(), _professors.end());
}
1
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 16:18  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Потому что делаете утечку памяти.
Понял. Спасибо.

Цитата Сообщение от DrOffset Посмотреть сообщение
Скопировать - больше никак.
Я понял.

Тут какая-то закавыка с возвращаемым значением. Причем если я возвращаю именно контейнер.
Я вот так могу делать. У меня всё работает. Но как только я начинаю возвращать контейнер - всё плохо.
C++
1
2
3
4
5
6
7
8
9
10
11
12
    Person* p = new Person("Oleg", 18);
    Person* prof = new Professor("Bjarne Stroustrup", 54);
 
    std::vector<Person*> persons(2);
    persons[0] = p;
    persons[1] = prof;
 
    for (auto person : persons)
        person->print();
 
    delete prof;
    delete p;
Причём вернуть дочерний класс как указатель на родителя я могу. А контейнер нею
DrOffset , вы не могли бы раскрыть это? Или сказать где про это прочитать.
Потому что std::vector не полиморфный тип.
Полиморфные у вас только Person <- Professor.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
19.08.2020, 16:23
Цитата Сообщение от schoolboy_ Посмотреть сообщение
вы не могли бы раскрыть это? Или сказать где про это прочитать.
Потому что std::vector не полиморфный тип.
Полиморфные у вас только Person <- Professor.
std::vector<Person*> и std::vector<Professor*> - это два совершенно разных типа, они не связаны отношением наследования, друг про друга ничего не знают.

Person и Professor - напротив, связаны наследованием.
1
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 16:32  [ТС]
DrOffset, спасибо вам. А вы не знаете, почему именно такая реализация ООП в С++. Кажется, что это очень криво. В каком нибудь С# этот код будет работать.
0
 Аватар для Nishen
1358 / 856 / 366
Регистрация: 26.02.2015
Сообщений: 3,814
19.08.2020, 16:40
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Кажется, что это очень криво.
Почему?
0
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 16:48  [ТС]
Цитата Сообщение от Nishen Посмотреть сообщение
Почему?
ну как же. очень естественная, по-моему, идея. Я могу возвращать дочерний класс как указатель на родителя.
Я даже могу принимать контейнер, содержащий ссылки на родительский класс:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void f(std::vector<Person*>& persons)
{
    for (auto person : persons)
        person->print();
}
 
Person* p = new Person("Oleg", 18);
Person* prof = new Professor("Bjarne Stroustrup", 54);
 
std::vector<Person*> persons(2);
persons[0] = p;
persons[1] = prof;
 
f(persons);
Но почему я не могу его вернуть?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
19.08.2020, 16:53
Цитата Сообщение от schoolboy_ Посмотреть сообщение
В каком нибудь С# этот код будет работать.
Не будет.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Кажется, что это очень криво.
Нет, не криво. Вы просто, видимо, не совсем понимаете что присходит.
2
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 16:56  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Нет, не криво. Вы просто, видимо, не совсем понимаете что присходит.
расскажите, пожалуйста. или скажите, где про это прочитать. Почему можно передавать контейнер, но нельзя его возвращать?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
19.08.2020, 17:04
Цитата Сообщение от schoolboy_ Посмотреть сообщение
ну как же. очень естественная, по-моему, идея.
Это частный случай, который на С++ реализуется средствами библиотеки (то, что конкретно вектор это не поддерживает - это не проблема C++).
Если где-то в C# вы встретили такое поведение, то там это точно так же реализовано средствами фреймворка. Сами по себе языки тут не при чем и в этом отношении солидарны.
В C# точно так же будет ошибка типизации наподобие такой:
Cannot implicitly convert type 'System.Collections.Generic.List<Profess or>' to 'System.Collections.Generic.List<Person> '
Добавлено через 19 секунд
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Почему можно передавать контейнер, но нельзя его возвращать?
Я же вам показал как возвращать?

Добавлено через 4 минуты
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Я даже могу принимать контейнер, содержащий ссылки на родительский класс
Постойте, вы же здесь совсем не то делаете.

Вы в функции ждете std::vector<Person*> & и передаете std::vector<Person*>.

А в примере с возвратом вы заявили тип std::vector<Person*>, но возвращаете по факту std::vector<Professor*>

- это же совсем разные вещи.
1
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 17:07  [ТС]
DrOffset, да. я был не прав. спасибо что помогли разобраться.
0
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
20.08.2020, 14:04  [ТС]
Я правильно понимаю, что "умные указатели" не тождественны "сырым указателям"? Полиморфизм подтипа в С++ возможен только через "сырой указатель" или ссылку?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
20.08.2020, 14:47
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Я правильно понимаю, что "умные указатели" не тождественны "сырым указателям"?
Правильно.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Полиморфизм подтипа в С++ возможен только через "сырой указатель" или ссылку?
Смотря что вы вкладываете в это. В целом полиморфизм работает и с ними.
1
 Аватар для Nishen
1358 / 856 / 366
Регистрация: 26.02.2015
Сообщений: 3,814
20.08.2020, 14:51
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Полиморфизм подтипа в С++ возможен только через "сырой указатель" или ссылку?
https://www.cyberforum.ru/post14765258.html

Добавлено через 30 секунд
Вот, я недавно писал из книги по паттернам. Там полиморфизм как раз используется с умными указателями.
2
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
20.08.2020, 15:17  [ТС]
Nishen, какой шаблон там реализовывается? Похоже на компоновщик.
0
 Аватар для Nishen
1358 / 856 / 366
Регистрация: 26.02.2015
Сообщений: 3,814
20.08.2020, 16:07
Цитата Сообщение от schoolboy_ Посмотреть сообщение
какой шаблон там реализовывается? Похоже на компоновщик.
Да никакой. Это просто костяк для реализации шаблонов.
0
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
22.08.2020, 19:06  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
std::vector<Person*> get_person() override {
    return std::vector<Person *>(_professors.begin(), _professors.end());
}
DrOffset, память в результирующем векторе будет выделяться при каждой вставке? Или компилятор оптимизирует данный код?
Мб для эффективности лучше создать результирующий вектор размером _professots.size() и туда скопировать по индексу?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
22.08.2020, 22:44
schoolboy_, нет. Память здесь выделяется один раз.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
22.08.2020, 22:44
Помогаю со студенческими работами здесь

наследование
Пытаюсь разобраться в наследовании Есть класс class File { public: struct comp { char num; // Имя переменной char st;...

Наследование
На основе класса «Массив» создать производный класс «Ассоциативный массив». Данный класс содержит массив указателей, каждый из которых...

наследование
Задача : Базовый класс: class Shape2D { public: Shape2D(); virtual ~ Shape2D(); virtual float Area( )= 0; virtual...

Наследование
Реализовать наследование классов квартиры,этаж,подъезд,дом

Наследование
Суть задачи: Реализуйте класс символьная строка,наследуйте от него класс двоичная строка. Реализуйте методы Show(от базовой строки) ...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru