|
5 / 5 / 0
Регистрация: 10.10.2014
Сообщений: 86
|
|||||||||||||||||||||
Как правильно использовать operator= при наследовании в полиморфных и неполиморфных классах31.08.2016, 21:07. Показов 2026. Ответов 7
Доброго времени суток! Изучаю книгу С. Прата "Язык программирования C++. Лекции и упражнения." Закончил 13-ю главу, посвященную наследованию и приступил к выполнению упражнений. Проблема возникла на этом упражнении:
Кликните здесь для просмотра всего текста
Союз программистов-меценатов собирает коллекцию бутылочного портвейна. Для ее описания администратор союза разработал класс Port, Завершив определения методов для класса Port, администратор написал производный класс Vintage Port, прежде чем был уволен
а. Первое задание — нужно заново создать определения методов Port, т.к. предыдущий администратор уничтожил свой код. б. Второе задание — объясните, почему одни методы переопределены, а другие нет. в. Третье задание — объясните, почему функции operator= () и operator« () не определены как виртуальные. г. Четвертое задание — обеспечьте определения для методов VintagePort. В общем и целом все понятно, но увидев пункт "в" я встал в ступор. Функция operator<<() не может быть виртуальной, т.к. она friend. Но почему operator=() не виртуальная? Внимательно проглядел код последних примеров из книги - operator=() не виртуальная, но я почему-то в свое время это забыл и при выполнении упражнений с полиморфным наследованием делал ее виртуальной, и все работало. Покопавшись еще, я совсем запутался, к примеру сделав ф-ю operator= в предыдущем упражнении не виртуальной я получил рабочую программу, хотя вроде и не должно бы: Кликните здесь для просмотра всего текста
Как это работает? Если мы оперируем ссылками на базовый класс, а operator=() не виртуальная (т.е. не используем таблицу виртуальных методов, и компилятор смотрит на тип указателя), то при использовании операции присваивания должна использоваться БАЗОВЫЙ_КЛАСС::operator=(), и соответственно, копироваться только базовая часть! Но в моем коде все прекрасно копируется, кроме того, получается присвоить объекту одного производного класса объект другого производного класса! У меня ощущение, что я блуждаю в 3-х соснах. Объясните, пожалуйста, как это работает, и как правильно использовать operator=() при полиморфном наследовании и без него. Заранее благодарю.
0
|
|||||||||||||||||||||
| 31.08.2016, 21:07 | |
|
Ответы с готовыми решениями:
7
Как правильно использовать деструктор исключений в наследующих классах? как использовать число во всех классах как объявить правильно tr и как его использовать при вызове функции? |
|
Модератор
13773 / 10966 / 6491
Регистрация: 18.12.2011
Сообщений: 29,244
|
|
| 31.08.2016, 21:15 | |
|
0
|
|
|
5 / 5 / 0
Регистрация: 10.10.2014
Сообщений: 86
|
||||||
| 31.08.2016, 21:45 [ТС] | ||||||
|
zss, пардон, под вечер совсем окосел. Самое обидное, что ведь даже добавил выведение адресов, а все равно проглядел!
0
|
||||||
|
0 / 0 / 3
Регистрация: 03.07.2016
Сообщений: 22
|
|
| 02.09.2016, 11:24 | |
|
Операции присваивания не наследуются (стр 716 "Соображения по поводу операции присваивания"). operator<< в данном примере дружественная функция, она не может быть виртуальной - не член класса (там же 719 Прата).
Тоже думал об этом, додумался до написанного мной выше. И тоже читаю этот же учебник -
0
|
|
|
5 / 5 / 0
Регистрация: 10.10.2014
Сообщений: 86
|
|||
| 02.09.2016, 13:31 [ТС] | |||
|
Usagi,
По поводу operator=() по ходу решения задачи с портвейном(доставляют в этом учебнике подобные задачи) пришло соображение, почему так делают: Оперируя массивом указателей на базовый класс, мы не можем заранее знать на объект какого класса (базового, или одного из производных) указывает указатель. Теоретически пользователь может попытаться: 1)Присвоить объект производного класса базовому - тут все более менее нормально и при virtual op=() и при non-virtual вызовется оператор присваивания базового класса и мы заберем однозначно существующие данные-члены от объекта произв. класса; 2)Присвоить объект базового класса производному - а вот тут могут возникнуть проблемы: если у нас virtual op=(), то вызовется оператор присваивания производного класса, который, скопировав базовую часть, попытается обратится к данным-членам, которых у присваиваемого объекта базового класса попросту нет. Результат не определен. Если же у нас non-virtual op=(), то мы скопируем только базовую часть, не пытаясь обратиться к несуществующим данным. Смысла в подобных действиях мало (получится смешанный набор данных), но зато ошибок точно не будет. 3)Присвоить объект одного произв. класса объекту другого произв. класса. Тут можно см. п.2, с небольшими отличиями. Короче говоря, non-virtual op=() гарантирует что при использовании этой операции мы гарантированно скопируем только однозначно существующие данные, принадлежащие базовому классу. За всем остальным к ручному приведению типов, тогда уже пользователь берет ответственность целиком и полностью на себя. Как то так. Может, я опять что-то напутал, у меня в последнее время такое ощущение все чаще ![]()
0
|
|||
|
0 / 0 / 3
Регистрация: 03.07.2016
Сообщений: 22
|
|||||
| 02.09.2016, 15:03 | |||||
Если operator=() объявлен как виртуальный, всё равно будет вызвана операция базового класса, а потом производного. Модель открытого наследования, отношение "является". Единственное, что мне не понятно, почему его можно объявить виртуальным. А по учебнику - очень хорошая вещь. Даже купил, хотя и читаю в электроном виде. Прогресс? Конечно. Большая разница между "до" и "после". Добавлено через 11 минут
Добавлено через 13 минут
Если присваивать объект базового класса производному, то без явно определённого operator=() для присваивания базового класса производному или конструктора преобразования не сработает.
0
|
|||||
|
5 / 5 / 0
Регистрация: 10.10.2014
Сообщений: 86
|
|||
| 02.09.2016, 15:16 [ТС] | |||
0
|
|||
|
0 / 0 / 3
Регистрация: 03.07.2016
Сообщений: 22
|
|
| 02.09.2016, 16:40 | |
|
Да, через ссылки или указатели такое присваивание будет работать, но только для базовой (общей) части. Неявное восходящие преобразование же?
Я понял, что Вы имеете ввиду: что если работать через ссылки (указатели) и определён виртуальный оператор присваивания, то согласно таблице виртуальных функций при присваивании объекту производного класса объекта базового класса должен быть вызван оператор присваивания производного класса. В этом случае будет вызван только оператор присваивания базового класса. Даже где-то у Праты написано, что операция присваивания относится к специальным членам класса. У каждого класса свой оператор присваивания. Его нет нужды объявлять виртуальным. Я это имел ввиду. Для "глубокого копирования" просто берётся и явно определяется оператор присваивания в нужном классе. Это 703 страница Праты. Случай с динамическим выделением памяти (под "глубокое копирование") и без него.
0
|
|
| 02.09.2016, 16:40 | |
|
Помогаю со студенческими работами здесь
8
Как использовать один и тот же объект в разных классах? Общие подходы при создании игры: как правильно использовать графику? Как правильно использовать заголовочные файлы при раздельной компиляции в MS Visual Studio? Как правильно использовать стек, использовать вершину стека и т.п Как правильно создать динамический массив в классах (с использованием инкапсуляции , конструкторов , наследования ) Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
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. Пошагово создадим проект для загрузки изображения. . .
|