Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 67
Текст из файла (страница 67)
Если в классе содержится член-указатель, то для класса следует определить копирующие операции (копирующий конструктор и операцию присваива- ния); 510.4.4.1. Если класс содержит член-ссылку, то ему, возможно, следует определить ко- пирующие операции (копирующий конструктор и операцию присваивания); $10.4.6.3. Если классу требуются копирующие операции или деструктор, то ему вероят- но потребуются конструктор, деструктор, операция присваивания и копи- рующий конструктор; 810.4.4.1. В операции присваивания проверяйте возможность самоприсваиваний; $10.4.4.1. При написании копирующего конструктора следите за тем, чтобы были ско- пированы все элементы (остерегайтесь умолчательной инициализации); $10.4.4.1. Добавляя новый член к существующему классу, проверяйте необходимость модификации конструкторов с целью корректной инициализации новых чле- нов; 510.4.6.3.
згз 1О.б.упражнения 16. 17. 18. 19. 10.6.Упражнения 1. 2. 3. 4. 5. б. 7. 8. 18. 11. Пользуйтесь перечислениями лля объявлений целых констант в классе; ф10.4.б.2. Избегайте зависимости от порядка конструирования глобальных объектов и объектов в пространствах имен; 910.4.9. Для минимизации зависимости от порядка конструирования объектов при- меняйте флаги первого использования; 910.4.9. Помните, что временные объекты уничтожаются в конце вычисления пол- ных выражений, в которых они созданы; 910.4.!О. (*1) найдите ошибку в .Рые::а~И уеаг() в 910.2.2. затем найдите еше две ошибки в версии из в!0.2.7.
(*2.5) Скомпилируйте и проверьте работу 2)аге. Переработайте этот класс для представления даты в виде «количество дней после 1/1/1970», (*2) Найдите какой-либо коммерческий вариант типа 2)аге. Покритикуйте предоставляемые им возможности. Обсудите это с другими пользователями. (*1) Как вы обратитесь к хеГ НеТаи» из класса Х>ате, находящегося в простран- стве имен СЬвло (910.3.2).
Предложите по крайней мере три разных способа. ('2) Определите класс Нагорят, который хранит числа из интервалов, ука- занных аргументами конструктора. Напишите функции для вывода гисто- грамм. Обрабатывайте ошибки выхода из диапазона значений. (*2) Определите несколько классов для представления случайных чисел с раз- ными законами распределения (например, равномерным или экспоненци- альным). В каждом классе должен быть конструктор, задающий параметры распределения, и функция агам ! ), возврашаюшая следуюшее случайное чис- ло. (*2.5) Дополните класс ТаЫе возможностью хранения пар (имя, значение). Затем модифицируйте программу-калькулятор из Эб.! таким образом, чтобы она использовала класс ТаЫе вместо»яар. Сравните две версии.
(*2) Перепишите 7вове из 97.10!7] в виде класса с конструкторами, деструк- тором и т.д. Определите дерево с узлами Тяояе в виде класса с конструктора- ми, деструктором и т.д. (*3) Определите, реализуйте и протестируйте класс Тлцег (множество целых). Предоставьте операции объединения множеств, пересечения и симметрич- ной разности. (*1.5) Модифицируйте класс Тягхег во множество узлов Мове, где Жо«(е — оп- ределяемая вами структура.
(*3) Определите класс для анализирования, хранения, вычисления и печати простых арифметических выражений, состоящих из целых констант и опера- ций», —, * и !. Открытый интерфейс должен выглядеть так: Глава 10 Классы 324 с1аее Ехрг ( У... рий№№е: Ехрг(еопгх сйаг*); Ыг ега1(); гоЫ ргйи ( ); Строковый аргумент конструктора Ехрг::Ехрг() является выражением. Функция Ехрг::ега1() возвращает значение выражения, а Ехрг::рг1иг() выводит представление выражения в соиг.
Программа может выглядеть примерно так: Ехргх("123!4+123*4-3"); соы« "х= "«х.ега1() «" ~п"; х.рг№пг ( ); Определите класс Ехрг дважды: один раз для его представления выберите список связных узлов, а другой раз — строку. Поэкспериментируйте с разными способами печати выражения: с полной расстановкой скобок, в постфиксной нотации и т.д. 12. (*2) Определите класс Сйаг 4иеие так, чтобы открытый интерфейс не зависел от представления. Реализуйте Сйаг 4иеие в виде (а) связного списка и (Ь) вектора. Не беспокойтесь о многопоточности.
13. (*3) Разработайте класс таблицы символов и класс элементов этой таблицы для какого-либо языка. Посмотрите на какой-нибудь компилятор для этого языка, чтобы узнать, как в действительности выглядит таблица символов. 14. ('2) Модифицируйте класс выражений из 010.6(1Ц таким образом, чтобы он мог обрабатывать переменные и операцию присваивания. Воспользуйтесь классом таблицы символов из 010.6[13). 15. (*1) Дана программа: №1пс1иИе <1омгеат> №пг та(п () ( еЫ::еоиг« "Недо, погЫ! ~п" ~ ) Модифицируйте ее так, чтобы она выводила №п1(1а11ае Не(1о, погЫ! С1еап ир Не вносите при этом никаких изменений в функцию ига№и () .
16. (*2) Определите класс Са1еи1агог так, чтобы большая часть его реализации со стояла из функций 06.1. Создавайте калькуляторы и активизируйте их лля ввода из е№и, из командной строки, для строк программы. Реализуйте вывод в разные приемники. 10.6. Упражнения 325 17. ('2) Определите два класса, кахцгый со слгалгическим членом, так, чтобы конструирование статического члена использовало ссылку на другой ставгический член. Где такое может встретиться в реальном коде? Как нужно модифицировать эти классы, чтобы устранить в конструкторах зависимость от порядка? 18. ('2.5) Сравните класс Эаге (910,3) с вашими решениями упражнений 85.9113] и 97.10[19).
Обсудите найденные ошибки и возможные различия в сопровождении каждого из решений. 19. ("3) Напишите функцию, которая получает в качестве аргументов )зггеалг н яесгог<згпвй>, а порождает тар<згпв8, яесгог<(лт», содержащий каждую строку и частоту ее вхождения. Прогоните программу на текстовом файле с количеством строк, не менее !000, разыскивая при этом не менее 1О слов. 28. ('2) Возьмите класс Евггу из 8С.8.2 н моднфицируйте его таким образом, чтобы каждый член объединения всегда использовался в соответствии с его типом. Перегрузка операций Когда я использую оюво, оно означает то, что я хочу им выразшнь, не больше и не меньше. — Шалтай-Болтай Нотация операций — функции-операции — бинарные и унарные операции— предопределенный смысл операций — операции и пользовательские типы— операции и пространства имен — комплексный тип — операции в виде функций-членов и глобальных функций — смешанная арифметика — инициализация — копирование — преобразования — литералы — функции полдержки— операции приведения типов — разрешение неоднозначности — друзья — члены и друзья — объекты больших размеров — присваивание и инициализация — индексирование — операция вызова функции — разыменование — инкремент и декремент — класс строк — советы — упражнения.
11.1. Введение В любой технической области — и в большинстве не технических — вырабатываются свои стандартные обозначения, помогающие наглядно представлять и обсуждать часто используемые концепции. Например, из-за длительного знакомства с формой записи хзу*е она для нас намного яснее и понятнее, чем фраза умножить у ни г и нрибивить резульи~от и х Невозможно переоценить важность кратких нотаций для общепринятых операций.
Как и большинство других языков программирования, С++ поддерживает набор операций для встроенных типов. Однако большинство концепций, для которых традиционно используются операции, не относятся ко встроенным типам языка С++, и их нужно представлять пользовательскими типами. Например, если вам 328 Глава ) 1. Перегрузка операций нужны комплексная арифметика, матричная алгебра или символьные строки, в языке С++ вы используете классы для представления этих концепций. А если для этих типов данных определить смысл действия стандартных операций, то работа пользователя с объектами этих классов становится более простой и наглядной по сравнению с использованием лишь традиционной функциональной нотации.
Например, У очень упрощенный класс сотр!ех с1ат соер1сх ( аоиые ге, ии; риЫ!с: совр!ох(аоиые г, аоиые !): ге(г), ии (!) ( ) совр)гх орега!ого (сотр1сх); сотр(ех орега1ог* (сотр1сх); )) реализует концепцию комплексных чисел. Комплексное число представлено здесь в виде набора двух вещественных чисел и дополнено арифметическими операциями э и * над этим новым типом данных. Программист в классе сошр!ех определяет функции-члены орега!огэ () и орегагог* (), которые и задают смысл и порядок работы операций ь (сложение) и * (умножение) над объектами типа сотр1ех. Если Ь и с имеют тип согпр1ех, то Ь+с означает функциональный вызов Ь. орегагог-ь (с) . Теперь для типа сотр!ех мы можем применять нотацию, принятую в математической литературе для комплексных чисел: гоЫу'( ) ( соер)ах а = соер1сх (1, 3.
1); сотр!ех Ь = сотр1ах (!.2,3); сотр!ах с = Ь | а = Ьэс; ь = ь+с.а; с = а*Ььсогир1ех (1, 2) При этом сохраняются обычные правила приоритета операций, так что второе выражение в представленном примере означает Ь=Ь+ (с*а), а не Ь= (Ьэс) "а. Наиболее очевидные случаи перегрузки операций (то есть переопределения операций для нового типа) относятся к конкретным типам данных (э10.3). Но, разумеется, полезность определяемых пользователем операций выходит за эти рамки. Например, при проектировании общих и специализированных интерфейсов программных систем часто приходится переопределять поведение даже таких операций, как ->, () и ().
11.2. Функции-операции 329 11.2. Функции-операции Можно перегружать следующие операции; «= « »= » ав [) >* йе1еге юХегете [ ) незя[) пеи яо(о'$(сотр1ех а, сотр1ех Ь) ( сотргех с = а в Ь; сотргех й = а. орегагогв (Ь ); ,У сокран(енноя форма У явный вызов Оба инициализирующих выражения в данном примере эквивалентны друг другу. Речь идет об операции возведения в степень. — Прим.