Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Sb97809

.pdf
Скачиваний:
2
Добавлен:
13.02.2021
Размер:
441.54 Кб
Скачать

МИНОБРНАУКИ РОССИИ

––––––––––––––––––––––––––––––––––––––––––––––––––––

Санкт-Петербургский государственный электротехнический университет «ЛЭТИ» им. В. И. Ульянова (Ленина)

–––––––––––––––––––––––––––––––––––––––––––

Н. И. КУРАКИНА Е. С. СУЛОЕВА

ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ НА С++

Учебное пособие

Санкт-Петербург Издательство СПбГЭТУ «ЛЭТИ»

2019

1

УДК 004.43(07) ББК З 973.2-018я7

К93

Куракина Н. И., Сулоева Е. С.

К93 Объектно-ориентированное программирование на С++: учеб. пособие. СПбГЭТУ «ЛЭТИ», 2019. 46 с.

ISBN 978-5-7629-2473-3

Представлен материал, необходимый для освоения дисциплины «Информатика» и «Информационные технологии», позволяющий студентам изучить навыки современного практического программирования. Предметом изучения курса является объектно-ориентированное программирование на языке Си++. В пособии последовательно и методично излагаются вопросы использования объектно-ориентированного подхода к созданию программ.

Предназначено для студентов направления «Приборостроение», также может быть использовано преподавателями вузов и аспирантами.

УДК 004.43(07) ББК З 973.2-018я7

Рецензенты: кафедра прикладной математики и информатики Высшей школы технологий и энергетики СПбГУПТД; д-р техн. наук В. Г. Бурлов (РГГМУ).

Утверждено редакционно-издательским советом университета

в качестве учебного пособия

ISBN 978-5-7629-2473-3

© СПбГЭТУ «ЛЭТИ», 2019

2

ВВЕДЕНИЕ

Компьютерная революция началась с машин, поэтому многие языки программирования ориентированы на машины. Однако компьютер – не столько машина, сколько инструмент, расширяющий возможности человеческого разума. Объектно-ориентированное программирование стало одним из направлений на пути превращения компьютера в выразительное средство.

Предлагаемое учебное пособие познакомит с основными концепциями объектно-ориентированного программирования, а именно программирования на С++.

Одна из причин успеха С++ заключается в том, что проектировщики языка стремились не просто превратить С в объектно-ориентированный язык, но также решить ряд других проблем, с которыми в наше время сталкиваются разработчики, особенно имеющие большой опыт программирования на С.

Главной целью разработки С++ является повышение эффективности. Источников этого повышения много, но язык спроектирован так, чтобы по возможности помочь программисту, не отягощая его искусственными правилами или требованиями об использовании некоторого ограниченного набора средств. Даже если вы продолжите писать С-образный код, переход на С++ сразу же принесет пользу. С++ обеспечил более качественную проверку типов и анализ данных на стадии компиляции. В С++ практически исчезла необходимость в использовании препроцессора для подстановки значений и макросов, что раньше приводило к трудноуловимым ошибкам. В С++ появились ссылки, обеспечивающие более удобную передачу адресов в аргументах и возвращаемых значениях функций. Механизм перегрузки функций существенно упростил работу с именами, поскольку теперь одно и то же имя может быть присвоено разным функциям. Пространства имен также улучшают контроль над использованием имен в программе. Существует еще множество мелких усовершенствований, которые делают С++ более надежным языком по сравнению с С.

Данное пособие предназначено для лиц, имеющих опыт работы на процедурных языках программирования, в частности на языке С. Излагаемый материал проиллюстрирован многочисленными примерами и задачами, что обеспечивает легкость понимания и усвоения предмета.

Объектно-ориентированное программирование – это новый подход (метод) программирования, в основе которого лежит понятие объекта. Объект- но-ориентированный подход не ограничивается узкой специализацией. Он дает программисту средства представления элементов в пространстве задачи.

3

Таким образом, объектно-ориентированное программирование (ООП) позволяет описать задачу в контексте задачи, а не в контексте того компьютера, на котором она будет решаться.

Объект – это логическая единица, которая содержит данные и правила (методы) обработки этих данных. В С++ в качестве правил выступают функции, таким образом, объект – это данные + функции, работающие с этими данными. Внутри объекта данные и функции могут быть частными или закрытыми (private), защищенными (protected) или открытыми (public).

Объектом является переменная, определенного пользователем типа, при этом основными характеристиками объектно-ориентированного программирования являются:

инкапсуляция;

полиморфизм;

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

абстракции типов.

Инкапсуляция – это объединение в единое целое некоторой группы данных и некоторой группы функций. При этом свойства объектов хранятся в структурах данных, поведение объекта реализуется при помощи функций, называемых функциями-членами.

В объекте реализован механизм защиты данных и функций. Полиморфизм – возможность использования одного имени для логиче-

ски связанных, но различных целей. Пример: выполнение одинаковых действий над различными типами данных.

Наследование – механизм, позволяющий одним объектам наследовать свойства других объектов. При помощи наследования реализуется иерархия объектов.

Для определения уровня доступа в С++ используется три ключевых слова: public, private, protected. Эти спецификаторы доступа указывают, кто может работать с объявлениями членов класса, следующими за ними. Спецификатор public означает, что следующие объявления доступны для всех. Спецификатор private означает, что доступ к следующим объявлениям возможен только из функции данного типа. При попытке обратиться извне к закрытому (private) члену класса происходит ошибка компиляции. Спецификатор protected используется при наследовании. Производные классы могут обращаться к защищенным (protected) членам класса, но доступ к закрытым (private) членам для них запрещен.

4

1. ИМЕНА ЗАГОЛОВОЧНЫХ ФАЙЛОВ В С++

По мере развития С++ производители компиляторов выбирали разные расширения для заголовочных файлов. Кроме того, в операционных системах устанавливаются различные ограничения для имен файлов, прежде всего – на длину имени. Все это создало проблемы с переносимостью исходных текстов. Для сглаживания этих различий в стандарте была использована схема, при которой длина имени не ограничивается восемью символами, а расширение не указывается. Например, рассмотримстаруюдирективудлявключенияфайлаiostream.h:

#include <iostream.h>

Теперь эта директива выглядит так:

#include <iostream>

Транслятор обрабатывает директивы включения в соответствии со спецификой конкретного компилятора и операционной системы. При необходимости он усекает имя файла и добавляет к нему расширение.

Библиотеки, унаследованные из языка С, сохранили традиционное расширение .h. Впрочем, их можно использовать при включении в современном стиле С++, для чего имя файла снабжается префиксом с.

Например:

#include <stdio.h> #include <stdlib.h>

Теперь он выглядит так:

#include <сstdio> #include <сstdlib>

Это правило распространяется на все стандартные заголовки С. Новая схема не тождественна старой: с расширением .h используется традиционный вариант включения, а без него – новая схема включения с применением шаблонов. Смешение двух форм в одной программе не рекомендуется.

2.СТРОКОВЫЕ ПЕРЕМЕННЫЕ В С++

ВС строка символов представляет собой символьный массив. Это не более чем простая группа символов в памяти, и программисту при выполнении всех операций необходимо контролировать длину, признак окончания строки и другие характеристики.

Стандартный класс С++ string предназначен для всех низкоуровневых манипуляций с символьными массивами и исключает потери времени и ошибки, с которыми постоянно сталкивались программисты.

5

Чтобы использовать в программе объекты string, необходимо включить в нее заголовочный файл С++ <string>. Класс string определен в пространстве имен std, поэтому в программу включается директива using. Благодаря перегрузке операторов синтаксис директивы string интуитивно понятен.

#include <string> #include <iostream> using namespace std; main () {

{string s1, s2; //Пустые строки

string s3=”Hello, World.”; // Инициализированная строка string s4(”I-am”); // Другой пример инициализации s2=”Today”; // Присваивание

s1=s3+” ”+s4; //Слияние строк

s1+=”8”; //Присоединение новых символов к строке cout << s1+s2+”!”;

}

Первые две строки – s1 и s2 – создаются пустыми, а строки s3 и s4 иллюстрируют два эквивалентных способа инициализации объекта string символьными массивами. Любому объекту string можно присвоить новое значение оператором =. Прежнее содержимое строки замещается данными, находящимися в правой части оператора присваивания. Удаление старых данных происходит автоматически. Объединение (конкатенация) строк осуществляется оператором +, который также позволяет объединять символьные массивы с объектами string. Для присоединения объекта string или символьного массива к другому объекту string можно воспользоваться оператором +=. Так как потоки ввода-вывода умеют работать с объектами string, чтобы вывести такой объект, достаточно передать в cout его или выражение, результат которого относится к типу string, как в приведенном примере.

3. КЛЮЧЕВЫЕ СЛОВА BOOL, TRUE, FALSE

До того, как булев тип был включен в стандарт С++, программисты использовали разные приемы при работе с логическими значениями, что вызывало ряд проблем.

В стандарте С++ тип bool имеет два допустимых состояния, выраженных встроенными константами true (целое число 1) и false (целое число 0). Все три имени являются ключевыми словами. Кроме того, некоторые элементы языка были адаптированы для новых типов:

6

Элемент

Использование с bool

&& || !

Получают аргументы типа bool и выдают результат типа bool

< > <= >= == !=

Выдают результат типа bool

If for while do

Условные выражения преобразуются в значения типа bool

?:

Первый операнд преобразуется к значению bool

Поскольку во многих существующих программах логические значения представляются типом int, компилятор производит автоматическое приведение от int к bool (ненулевые значения интерпретируются как true, а нулевые значения – как false). В идеальном случае компилятор выдает предупреждение с рекомендацией о внесении исправлений.

4. ССЫЛКИ В С++

Функции, получающие аргументы при вызове, создают внутренние копии этих аргументов. Этот механизм называется передачей по значению. При вызове функции выделяется временная область памяти для хранения аргументов во время выполнения функции. После завершения функции выделенная память освобождается и аргументы сохраняют свои прежние значения.

Пример:

void swap (int i, int j) { int tmp;

tmp= i; i=j; j=tmp ;}

Таким образом, изменение локальных переменных i, j не отражается на внешнем объекте, поскольку они занимают разные области памяти.

Когда необходимо изменить значение, параметры объявляют как указатели при помощи символа *. В определенном смысле указатель является псевдонимом для другой переменной. Так, если вместо обычного значения передать функции Указатель, фактически передаются псевдонимы переменных, что позволяет функции модифицировать их значения.

Пример:

void swap (int *i, int *j) { int tmp; tmp=*; *i=*j;

*j=tmp ;} swap (&a, &b);

При вызове используются указатели на аргументы.

Указатели в С и С++ работают примерно одинаково, но в С++ появился новый способ передачи адресов функциям. В С++ есть возможность сообщить компилятору о необходимости генерировать вызов по ссылке другим

7

способом. Перед параметрами в прототипе и в объявлении функции ставится & – ссылочный параметр.

void swap (int &i, int &j) {int tmp; tmp=i; i=j; j=tmp ;}

swap (a, b);

Следовательно, передача по ссылке позволяет функциям изменять внешние объекты, как и передача указателей.

Возможно объявление ссылочных переменных, когда они не являются параметрами функции, например, непараметрические ссылки или независимые ссылки. Независимая ссылка должна быть инициализирована при ее объявлении, т. е. ссылке должен быть присвоен адрес переменной, объявленный до нее. Между переменной и ссылкой нет различия, ссылка становится псевдонимом переменной.

Пример:

#include <iostream> using namespace std; main ()

{int j, k; int & i=j; j=10;

cout << i; k=121;

i=k; cout <<j;

}

i – независимая или непараметрическая ссылка, которая является псевдонимом элемента j.

5. ТИП VOID

Существует еще один тип, который может использоваться с указателями, – тип void. Если в программе определяется указатель типа void*, это означает, что ему может быть присвоен адрес произвольного типа (тогда как указателю int* можно присвоить только адрес переменной типа int).

Пример: main ()

{void *vp; char c;

8

int i; float f; double d; vp=&c; vp=&i; vp=&f; vp=&d;

}

После присваивания void* вся информация о типе, связанном с данным адресом, теряется. Это означает, что перед использованием указателя его необходимо привести к правильному типу.

Пример: main ()

{ int i=99; void *vp=&i;

//Разыменование указателя на void запрещено vp=3; //Ошибка компиляции

// Перед разыменованием необходимо выполнить приведение к типу int *((int*)vp)=3;

}

Приведение (int*)vp сообщает компилятору, что тип void* при разыменовании должен интерпретироваться как int*.

6. ОПРЕДЕЛЕНИЕ ПЕРЕМЕННЫХ НЕПОСРЕДСТВЕННО ПЕРЕД ИСПОЛЬЗОВАНИЕМ

Между С и С++ существуют значительные различия в определении переменных. Оба языка требуют, чтобы переменные определялись перед использованием, но С заставляет определять все переменные в начале области видимости, чтобы компилятор мог выделить память для этих переменных.

Язык С++ позволяет определять переменные в произвольной точке области видимости, т. е. переменная может определяться непосредственно перед использованием. Кроме того, возможна инициализация переменных в точке определения, что предотвращает некоторые коды ошибок.

Переменные также могут определяться в управляющих выражениях циклов for и while, в условиях команд if и в критериях выбора команды switch. Рассмотрим пример определения переменных непосредственно перед использованием.

9

#include <iostream> using namespace std; main () {

{//Начало новой области видимости int q;

// Определение переменных перед использованием for(int i=0; i<100; i++) {

q++;

// Определение в конце области видимости int p=12;

}

int p=1; //Другая переменная p

} //Завершение области видимости, содержащей q и внешнюю переменную p

while (char c=getch() != ‘q’) cout << c;

}

Во внутренней области видимости переменная p определяется перед концом области видимости. Это объявление абсолютно бесполезно, но оно показывает, что переменные действительно могут определяться в любой точке области видимости. То же самое можно сказать о переменной p из внешней области видимости.

Определение i в управляющем выражении цикла for – пример определения переменной прямо в момент использования. Область видимости i ограничивается данным циклом for, поэтому ничто не помешает заново определить переменную с именем i для следующего цикла for.

Использование определения переменных в командах while, if, switch происходит значительно реже определения в циклах for. Возможно, это объясняется ограничениями синтаксиса. Например, выражение не может содержать круглых скобок, т. е. следующая конструкция невозможна:

while ((char c=getch()) != ‘q’)

Без круглых скобок результат выглядит не так, как следовало ожидать. Проблемы возникают из-за того, что оператор != обладает более высоким приоритетом, чем =, поэтому переменной char в конечном счете присваивается значение bool, приведенное к типу char.

10

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]