10. Аргументы командной строки
Иногда бывает необходимо запустить приложение через консоль, и заодно передать ему некоторые аргументы. До этого мы оставляли функцию mainбез аргументов, однако в коде многих программ можно встретить аргументы int argc и char* argv[]. Первый- это количество аргументов, а второй- массив строк. Примечательно, что первый аргумент- это всегда полный путь к программе. При передаче через консоль аргументы разделяются пробелами. Вот самая простая демонстрация:
Программа просто выводит полученные аргументы.
Примечание
С помощь данного метода удобно передавать имя файла функцию.
Оглавление
81
11. Введение в объектно-ориентированное
программирование
11.1 Объекты
При изучении объектно-ориентированного программирования (ООП) наибольшей проблемой является использование новой терминологии и понимание нового подхода к решению старых задач. Для начала дадим определение: ООП – система принципов и способов организации представления программы в виде совокупности объектов
, каждый из которых является экземпляром определенного класса.
С++ представляет именно другую методологию программирования, если в С вы использовали функцию, как основополагающую единицу
(процедурное программирование), то теперь ее заменит класс. Поясним, что такое классы и объекты:
Классы в С++ — это абстракция, описывающая методы, свойства, ещё не существующих объектов. Объекты — конкретное представление абстракции, имеющее свои свойства и методы. Методы - функции классов.
Приведем простой пример класс – Автомобиль, объекты класса
Автомобиль: ВАЗ-2105, BMWX5. Класс задает основные характеристики и функции, который должен иметь любой его экземпляр и действительно мы можем сказать, что и BMW, и ВАЗ являются автомобилями.
Оглавление
82
11.2 Наследование
Еще одним столпом ООП является наследование. Наследование - концепция объектно-ориентированного программирования, согласно которой абстрактный тип данных может наследовать данные и функциональность некоторого существующего типа, способствуя повторному использованию компонентов программного обеспечения.
Проще говоря, если у вас есть класс, но вам нужно его расширить или добавить дополнительные функции/переменные, то вы можете сделать еще один класс на основе этого. Например, класс Внедорожник, который будет являться наследником класса Автомобиль, т.е. Внедорожник будет иметь все те же функции/данные, что и класс родитель, однако будет дополнен некоторыми особенностями.
Немного терминологии,
Класс, опредёленный через наследование от другого класса, называется: производным классом, классом потомком (англ. derived class) или подклассом (англ. subclass). Класс, от которого новый класс наследуется, называется: предком (англ. parent), базовым классом (англ. base class) или суперклассом (англ. parent class).
Оглавление
83
11.3 Инкапсуляцияи полиморфизм Если говорить кратко инкапсуляция – это сокрытие данных. На самом деле за кажущейся очевидностью кроется нечто большее. Этот принцип позволяет нам работать с объектами
непосредственно через интерфейс класса, даря возможность не думать, как он устроен и, что более важно, не давая как-то вмешаться в уже отлаженный механизм. Как вы вскоре увидите принято большинство данных классов делать скрытыми.
Опять же аналогия с автомобилями производитель сделал машину, которая выполняет необходимые требования владельца, однако для того, чтобы ей пользоваться, не нужно знать, как она работает.
Способность объекта использовать методы производного класса, который не существует на момент создания базового, называется полиморфизмом (греч, polymorphos многообразный). Чтобы было понятнее, представим, что вы хотите использовать объекты 3х различных классов, которые являются наследниками одного класса. Вы можете работать с каждым из них по отдельности, но это не очень удобно. Гораздо проще работать с ними как с объектами одного класса, вот здесь и поможет полиморфизм, он поможет работать с разными объектами, как с элементами одного класса.
Возьмем мастерскую, занимающуюся ремонтом, где ремонтируются мотоциклы, легковые автомобили, катера и т.д. Очевидно, будет проще вводить данные по унифицированной системе для всех транспортных средств, а также осуществлять поиск и совершать иные операции. Так что создав класс, Транспортное_средство и объявив его предком (настроить общие функции), можно существенно облегчить процесс.
Оглавление
84
11.4 Абстракция Абстракция стоит отдельно от «трех китов ООП»: полиморфизма, наследования и инкапсуляции. Однако о ней тоже следует упомянуть.
Абстракция данных – выделение существенных характеристик объекта, существенных в рамках решаемой нами задачи.
Возьмем тот же автомобиль. Допустим, нашей задачей будет определить внешнее различие одного автомобиля от какого-то другого (да, пример своеобразен, но он легко объясняет принцип абстракции).
Внешние признаки автомобиля: цвет, форма автомобиля и т.д. Для этих признаков мы и создадим поля класса для будущего объекта автомобиля.
Остальные признаки сравнения,
такие как двигатель, размер колес автомобиля, его вес и т.д. нам не нужны. Так как мы сравниваем только по внешним признакам, соответственно и поля класса для будущих объектов создаются только по внешним признакам (в нашем случае).
Комментарии Конечно, приведенные выше определения и примеры не являются точными и подробными, они лишь призваны познакомить с основными концепциями, большинство из прочитанного будет раскрыто позднее, так как создание большого разрыва между теорией и практикой не поспособствует успешному освоения материала
Оглавление
85
12. Классы
Основным отличием C++ от C является наличие классов, которые предоставляют возможность моделирования объектов реального мира. Это происходит посредством совмещения методов, т.е. функций классов и данных(+ еще несколько особенностей, но об этом позже).
Лучше увидеть это на практике:
Объявление класса начинается с ключевого слова class. После имени открываются фигурные скобки – это тело цикла, здесь располагаются данные (переменные) и функции класса (методы). Открывает тело слово private, оно означает, что к следующим методам/данным могут получить доступ только методы данного класса, например в данной программе нельзя записать ex.length=7, однако методы ex.square() и ex.perimeter() будут работать. Ключевое слово publicозначает, что следующие методы или данные пользователь может вызывать из других функций. Ключевые слова могут быть объявлены и не в таком порядке, кроме того,
Оглавление
86 privateможно не объявлять, т.к. элементы класса по умолчанию скрыты.
После объявления и определения методов в классе, можно приступать к работе с элементами класса.
В mainсоздается объект exкласса example, далее через операцию точки (.) получается доступ к 3 методам. 2 из них возвращают значения целочисленного типа. Так что можно вывести результат через поток вывода.
При создании нового объекта класса создаются и новые данные (если не объявлены со словом static), однако не методы, что обусловлено экономией памяти, да и просто логикой.
Примечание.
Никогда не путайте структуры С и С++, большинство программистов используют структуры только для хранения данных (и это правильно); в
C++, в отличие от С, их возможности намного выше. В C++ структуры отличаются от классов только тем, что по умолчанию имеют тип public, в то время как классы – private.
Оглавление
87
13. Конструкторы и деструкторыПри создании экземпляра класса всегда вызывается функция, называемая конструктором. Если, как в предыдущей главе, она не определена то, такой конструктор называется конструктором по умолчанию.
Конструктор не может возвращать значения, однако передавать ему аргументы, при условии, что они прописаны в объявлении, можно. Характерной особенностью конструктора помимо обязательного вызова при создании, является то, что имя этой функции совпадает с именем класса, таким образом, его всегда можно отличить.
Как можно догадаться, деструктор является, в некоторой степени, противоположностью конструктора, то есть вызывается при уничтожении объекта, из этого логически следует, что деструктор не может иметь ни параметров, ни возвращаемого значения. Найти данную функцию в коде очень просто, так как она имеет имя класса со знаком «»перед. Основной задачей деструктора обычно является работа с памятью.
Модифицируем немного предыдущий класс:
Оглавление
88
Строка: example(): length(0), width(0) – это конструкторбезаргументов.
Строка: example(intl, intw ) : length(l ), width(w ) – это конструкторсдвумяаргументами
В этом примере представлено два конструктора: без аргументов и с 2 аргументами. Как вы могли заметить, присваивание параметров в конструкторах происходит не стандартно, такое решение программисты зачастую принимают из-за того, что это повышает удобочитаемость и логичность кода, однако обычный подход, в котором присваивание происходит в теле функции, здесь также сработает.
В программе деструктор, конечно, является просто примером и не выполняет тех функций, которые ложатся на него в проектах.
В заключении стоит лишь указать, что конструкторы и
деструкторы являются важной особенностью классов, первые удобно использовать если вам необходимо сделать некоторые операции сразу при определении(или хотя бы из-за того, что это удобно), что до вторых то их использование еще более важно, и в следующих главах это можно будет увидеть отчетливо.
Оглавление
89
14. Наследование
Пришло время рассказать еще об одной особенности языка
C++, которая существенно облегчает работу программиста. Итак, наследование – это процесс создания новых классов называемых наследниками или производными классами, из уже существующих или базовых классов. То есть, допустим, если у вас есть класс с нужными свойствами, но вам нужно написать еще несколько, при этом вам нельзя изменять базовый класс (возможно, его долго отлаживали или он необходим для каких-то частных объектов). Тогда вы можете наследовать этот класс, приписав к нему необходимые свойства. На рисунке 14.1 это представлено наглядно:
Рис 14.1
Что же, попробуем увидеть эту схему на примере:
Оглавление
90
Сразу можно заметить, что вместо ключевого слова private используется protected. Разница в том, что с помощью protected из наследников можно получить доступ к данным/методам, а из private – нет.
Для того, чтобы сделать класс наследником нужно после имени класса поставить двоеточие, а далее перечислить родителей (да их может быть несколько). Вы могли заметить немного необычное определение конструктора у наследника: после двоеточия вызывался конструктор родителя, это довольно встречающаяся практика, конструктор из производного класса получает данные, а для обработки полной или частичной, вызывается конструктор базового класса. При работе с созданным объектом все методы вызываются так, как будто объявлены в теле класса.
Представленная выше информация несет в себе цель познакомить студента с наследованием и дать минимальные практические навыки,
Оглавление
91 однако в вопросах наследования есть много тонкостей, которым нужно было бы выделить отдельную книгу, поэтому лучший способ изучения языка – практика.
15. Явное и неявное преобразование типов в C++
Среди них уже рассмотренный нами оператор static_cast (в разделе
6.2), оператор снятия константности (и volatile, но это ключевое слово используется редко) const_cast, а также операторы reinterpret_cast (для преобразования принципиально различных типов) и dynamic_cast (для преобразования полиморфных типов, связанных иерархией наследования).
Рассмотрим их синтаксис:
Оператор static_cast преобразует выражение одного статического типа в объекты и значения другого статистического типа
Оператор dynamic_castиспользуется для динамического приведениятипов во время выполнения программы
Что делают эти операторы было написано в первом абзаце.
Оглавление
92
16. Перегрузка операций
Когда уже определенная операция (к примеру, + или -) наделяется возможностью совершать действия над операндами нового типа, то такая операция – перегруженная. Перегрузка операций помогает упростить код программы.
Рассмотрим это утверждение на примере:
Оглавление
93
В листинге этой программы используется ключевое слово operator, с которым вы, вероятнее всего, столкнулись впервые. Именно это ключевое слово позволяет нам перегружать операции.
Сначала пишется возвращаемый тип (в данном случае Room), далее ключевое слово operator, а затем сама операция, которую следует перегрузить (мы перегружаем «+»). Такой синтаксис говорит компилятору о том, что если операнд принадлежит классу Room, то нужно вызвать функцию с таким именем, встретив эту арифметическую операцию в тексте программы.
Оглавление
94
17. Перегрузка функций
В C++ стала возможна перегрузка функций. Это понятие означает, что вы можете иметь несколько функций с одинаковыми именами. В самом деле, если вам нужно несколько функций, выполняющих приблизительно одну и ту же задачу, то будет намного проще иметь одно имя для всех. Но как же компилятор различит, какую функцию надо использовать? Ответ прост – по параметрам.
Ниже представлена программа, возводящая целые или вещественные числа в квадрат:
В листинге этой программы видно, что прототип функции rootобъявлен как и для вещественных, так и для целых чисел.
Оглавление
95
18. Потоки ввода и вывода В C для организации ввода и вывода (по крайней мере в этом пособии) были использованы функции scanf() илиprintf(), а также их аналоги для работы с файлами fprintf() иfscanf(). Однако в C++ практикуется несколько иной подход, а конкретнее: потоковые объекты.
Они имеют несколько преимуществ перед функциями. Первым является простота использования, вспомните, как нужно было форматировать ввод и вывод с помощью символов управления форматом (%d, %f, и т.д.), ничего подобного вы не встретите при использовании потоков, ибо каждый объект сам отвечает за то, как он выглядит на экране. Вторым весомым аргументом является возможность перегрузки операторов вставки(<<) и извлечения(>>), это позволяет работать с классами как со стандартными типами. Нельзя также не упомянуть о том, что использование потоков является лучшим способом записывать данные в файл, лучшим способом организовывать данные в памяти (что важно при работе с графическим интерфейсом).
Пример использования потоковых объектов можно увидеть ниже:
Итак, с первой строки мы сталкиваемся с неизвестной, пока что, библиотекой на самом деле, как не
трудно догадаться по названию, она содержит все необходимое для работы с данными. Далее идет строка: using namespace std. Дело в том, что в C++ есть такое понятие, как пространство имен, если вкратце, то оно помогает данным не пересекаться, т. е. если у вас есть две функции, объявленные в разных пространствах, то можно не
Оглавление
96 переживать, что будет использована одна, вместо другой. Директива usingобъявляет, что все объекты в коде принадлежат одному пространству имен. Есть еще один вариант:
Операция :: называется операцией глобального разрешения и отражает, что cin, cout являются объектами пространства std.
Так часто пишут, если нужно работать с множеством библиотек и, следовательно, с множеством пространств.
Далее в программе идет несколько cin (объектов ввода),cout(объектов вывода), а также операций вставки в поток(<<)и извлечения(>>). Смысл их работы выражается следующем: объект представляет собой поток, в который с помощью операции вставки помещаются данные, или с помощью операции извлечения считываются.
Оглавление
97
18.1 Иерархия библиотек ввода вывода
Говоря о вводе и выводе нельзя не упомянуть о связи библиотек, отвечающих за ввод и вывод. Как уже известно, одним их основных отличий программирования на C++ от C является применение принципов
ООП, в частности – наследования. Несколько наследований могут образовывать своеобразную иерархию:
Как видно класс iosнаследуется всеми классами.
Оглавление
98
18.2 Форматирование ввода и вывода
Как вы помните, в C для форматирования вывода использовались следующие символы: ‘\n’, ‘\t’, и т. д. Они также, использовались в вышеуказанном примере, тем не менее, потоки представляют больше способов организации ввода и вывода.
Основными являются манипуляторы, флаги форматирования и функции для работы с потоковыми объектами и установки флагов форматирования.
Оглавление
99
18.3 Манипуляторы
Манипуляторы – это инструкции форматирования, которые вставляются прямо в поток примеры: endlявляется манипулятором разделителя строк строки, его действие напоминает “\n”. setiosflags() – устанавливает (подождите, подождите) флаги форматирования, в данном случае флаг фиксированного вывода.
Ниже приведен список самых используемых манипуляторов:
Dec
Ввод/вывод данных в десятичной форме ввод и вывод
Endl
Вывод символа новой строки с передачей в поток всех данных из буфера вывод
Ends
Вывод нулевого символа вывод
Flush
Передача в поток содержимого буфера вывод
Hex
Ввод/вывод данных в шестнадцатеричной системе ввод и вывод
Oct
Ввод/вывод данных в восьмеричной форме ввод и вывод resetiosflags(long f)
Сбрасывает флаги, указанные в f ввод и вывод setbase(int base)
Устанавливает базу счисления равной параметру base вывод setfill(int ch)
Устанавливает символ заполнения равным ch вывод setiosflags(long f)
Устанавливает флаги, указанные в f ввод и вывод setprecision(int p)
Устанавливает число цифр после запятой вывод setw(int w)
Устанавливает ширину поля равной w вывод
Ws
Пропускает начальный символ-разделитель ввод
При использовании данных манипуляторов не забывайте, что манипуляторы действуют только на те данные, которые следуют за ними в потоке.
Оглавление
100