Вы находитесь на странице: 1из 20

Объектно-

ориентированное
программирование
Классы
2 СЕМЕСТР 3 ЛЕКЦИЯ

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 1


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

Программа Программа на
Машинные
на языке языке высокого
инструкции
ассемблера уровня (С++ и т.п.)
Уровень программирования
Облегчение восприятия, написания,
отладки, сопровождения

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 2


Объектно-ориентированное
программирование
Так, запись оператора цикла на С++:
for (int i=0; i<5; ++i) arr[i]=i;
разворачивается в ассемблерное порождение (конфигурация Debug):
0x0040131a movl $0x0,-0x2c(%ebp) // i=0
0x00401321 cmpl $0x4,-0x2c(%ebp) // i>4 ?
0x00401325 jg 0x00401338 // break !
0x00401327 mov -0x2c(%ebp),%edx // значение индекса
0x0040132a mov -0x2c(%ebp),%eax // значение для присваивания
0x0040132d mov %eax,-0x28(%ebp,%edx,4) // arr[i]=i
0x00401331 lea -0x2c(%ebp),%eax // в %eax – адрес i
0x00401334 incl (%eax) // ++i
0x00401336 jmp 0x00401321 // к следующей итерации
0x00401338 …
КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 3
Объектно-ориентированное
программирование
Рост объема программы требует повышения степени абстракции:
• структурирования и обобщения данных;
• скрытия и отвлечения от деталей реализации.
Первым средством абстрагирования в развитии программирования стали функции. Если
функция не использует глобальных переменных, для ее вызова достаточно знать ее
интерфейс.
Следующий шаг – введение пользовательских типов данных, позволяющих естественным
образом структурировать информацию (о товаре на складе, о студенте в группе, о рейсе
самолета и т.п.).
Далее пользовательские типы и функции работы с ними группируются в отдельные единицы
компиляции – модули (исходные файлы). Связи между модулями минимизируются с целью
упрощения сопровождения кода. Детали реализации скрываются от пользователя, ему
предоставляется лишь интерфейс.

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 4


Объектно-ориентированное
программирование
Понятие класса – дальнейшее развитие принципа абстрагирования. Класс объединяет данные
и функции их обработки, предоставляя пользователю интерфейс взаимодействия. Класс
является типом данных: этот тип, как и в случае базовых типов языка, определят
представление его данных в памяти, множество значений и множество операций. Конкретные
величины типа данных «класс» называются экземплярами класса или его объектами.
Понятие класса – основа ООП. Принципы ООП были разработаны еще в конце 60х гг. в языках
Simula-67 и Smalltalk, но получили свою эффективную и непротиворечивую реализацию лишь
с созданием С++.
ООП – парадигма программирования. Парадигма – комплекс теорий, стандартов и методов,
обеспечивающий иную организацию знаний.

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 5


Основные концепции ООП
Инкапсуляция – объединение данных с функциями их обработки в сочетании со скрытием
информации, ненужной для их использования. Инкапсуляция повышает уровень абстракции
программы, чем упрощается ее модификация. Так, реализация класса может быть изменена без
изменения программы, к примеру, класс может изменить способ хранения данных с массива на стек.
Наследование – возможность создания иерархии классов, где потомки наследуют свойства предков,
могут их изменять и добавлять новые. При этом отношение наследования отличается от отношения
включения тем, что потомок является предком. Повышение уровня абстракции программы путем
выделения общих свойств различных сущностей в одном классе предке уменьшает сложность
предметной области, сокращает объем программы и облегчает ее сопровождение. Пример:
абстрактный класс «фигура» с потомками «многоугольник», «эллипс» и т.п.
Полиморфизм – возможность использования в классах иерархии одного имени для обозначения
сходных по смыслу действий, а также гибкий выбор действия во время выполнения программы.
Первый пример полиморфизма – перегрузка функций, где подходящая реализация определяется
набором аргументов, другой – шаблоны функций (и классов), параметризующие тип. Но чаще
понятие полиморфизма связывают с механизмом виртуальных методов, обеспечивающим
корректный вызов методов потомков класса. Пример: абстрактный виртуальный метод перерисовки
в классе «фигура».

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 6


Классы (описание класса)
Класс – тип данных, определяемый пользователем (программистом – пользователем
языка), представляющий собой модель реальной сущности в виде данных и функций
работы с ними.
Данные и функции класса являются его членами. Данные класса называются полями
или свойствами, функции – методами. Общее синтаксическое описание класса:
class <имя>{
[private:]
<описание скрытых элементов>
public:
<описание доступных элементов>
}; // “;” в конце описания
Спецификаторы доступа private и public управляют видимостью членов класса:
• члены после спецификатора private видимы только внутри класса;
• члены после спецификатора public видимы и вне класса и формируют его интерфейс;
• по умолчанию неявно действует спецификатор private (см. описание выше);
• действие спецификатора распространяется до следующего спецификатора или конца класса.
КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 7
Классы (описание класса)
Поля класса могут:
• иметь любой тип, кроме типа этого класса (допускается указатель или ссылка на этот тип);
• быть описаны с модификатором const, при этом они инициализируются однажды и не
могут изменяться;
• быть описаны с модификатором static (статические поля), но не как auto, extern и register.
Инициализация полей не допускается (в стандарте языка до 2011 г.).
Методы класса могут объявляться с ключевым словом const. Константный метод:
• не может изменять значений полей класса;
• может вызывать только константные методы.
Методы чтения (read-only) полей класса описываются как константные.
Константный объект может вызывать только константные методы.
Классы могут быть объявлены вне любого блока (глобальные) и внутри блока,
функции или другого класса (локальные).

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 8


Классы (описание класса)
В качестве примера используем простейшую реализацию строкового класса “String”
(более эффективная реализация рассматривается в дальнейшем). Класс обеспечивает:
• инициализацию строковым литералом и другим объектом “String”;
• присваивание строкового литерала и другого объекта “String”;
• печать и правку символа по индексу.
class String {
char* _data; // Скрытые поля.
int _size; //
public:
String();
String(const char*);
...
int size() const { return _size; } // Константный метод чтения
}; // значения поля _size.
Метод size() определен внутри класса: он является внутренним (inline).
КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 9
Классы (описание объектов)
Время жизни и видимость объектов (экземпляров) класса подчиняется общим
правилам С++:
String emptyStr; // Объект, инициализированный по умолчанию.
String str(“Hello”); // Объект с явной инициализацией.
String strings[100]; // Массив объектов со значением по умолчанию.
String* dStr = new String(“world”); // Динамический объект.
String& ref=str; // Ссылка на объект.

При создании объекта выделяется память, достаточная для хранения всех его полей.
Инициализация выполняется конструктором. При выходе объекта из области
видимости он уничтожается с вызовом деструктора.
Доступ к public-членам объекта класса, как и в случае объектов структур,
осуществляется посредством операторов “.” и “->”:
int sz=str.size();
cout << dStr->size();

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 10


Классы (конструктор)
Конструктор инициализирует объект класса и вызывается автоматически при его
создании. Конструктор имеет свойства:
• конструктор не возвращает значение. Нельзя получить указатель на конструктор;
• класс может иметь несколько конструкторов (перегрузка конструкторов);
• конструктор, вызываемый без параметров, называется конструктором по умолчанию.
Конструктором по умолчанию также является конструктор, все параметры которого имеют значение
по умолчанию;
• если класс не содержит ни одного конструктора, компилятор создает его автоматически. Такой
конструктор вызывает конструкторы по умолчанию для полей класса;
• если класс содержит конструкторы с параметрами, но не содержит конструктора по умолчанию, то
создание объекта по умолчанию приведет к ошибке компиляции;
• конструкторы не наследуются;
• конструкторы нельзя описывать с модификаторами const, virtual и static;
• конструктор вызывается в каждой из синтаксических комбинаций:
• имя_класса имя_объекта[(параметры)]; // String emptyStr, str(“Hello”);
• имя_класса(параметры); // String sstr=String(“world”);
• имя_класса имя_объекта=выражение; // String strr=“Hello world”;
При конструировании строки emptyStr будет вызван конструктор по умолчанию, для
строк str, sstr и strr – конструктор от литерала – String(const char*)
КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 11
Классы (конструктор)
Рассмотрим определения двух конструкторов класса String (не-inline методы класса
определяются с помощью оператора разрешения области видимости “::”):
String::String() { // Конструктор по умолчанию.
_data = new char[(_size=0)+1]; // +1 для 0-символа
*_data=0;
}
String::String(const char* dt) {
_data = new char[(_size=strlen(dt))+1];
strcpy(_data,dt); // strcpy копирует все символы, включая 0-символ
}
Дополнительный способ инициализации полей объекта – использование списка
инициализаторов:
someClass::someClass(int val1, double val2)
: _field1(val1), _field2(val2), _field3(new char[5]) { ... }

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 12


Классы (конструктор копирования)
Конструктор копирования – особый конструктор с единственным параметром –
ссылкой на объект того же класса:
T::T(const T&) { ... } // T – имя класса
Этот конструктор вызывается при создании объекта копированием другого объекта:
• в синтаксической комбинации T t2=t1;
• при передаче объекта в функцию по значению;
• при возврате объекта из функции.
Если класс не снабжен конструктором копирования, компилятор создаст его
автоматически. Такой конструктор выполняет поэлементное копирование полей, что
является неприемлемым для полей-указателей.
Конструктор копирования для класса String:
String::String(const String& st) {
_data=new char[(_size=st._size)+1];
strcpy(_data,st._data);
}

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 13


Классы (деструктор)
Деструктор – особый метод, освобождающий память, занимаемую объектом.
Деструктор вызывается автоматически при уничтожении объекта.
T::~T() { ... } // T – имя класса
Деструктор:
• не имеет аргументов и возвращаемого значения;
• не может быть объявлен как const и static;
• не наследуется;
• может быть виртуальным.
Если класс не снабжен деструктором, компилятор автоматически создаст пустой
деструктор. Явный деструктор необходим для классов, чьи объекты выделяют память
динамически.
Деструктор для класса String:
~String() { delete [] _data; }

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 14


Классы (перегрузка операций)
C++ позволяет переопределять (перегружать) действие большинства операций для объектов
конкретного класса. Обозначения собственных операций вводить нельзя, можно перегружать
любые операции С++ за исключением:
. .* ?: :: # sizeof
Операции перегружаются с помощью функций-операций (операторов) с ключевым словом
operator, за которым следует знак переопределяемой операции:
тип operator операция (список параметров) { ... }
Операторы подчиняются правилам:
• при перегрузке сохраняется количество аргументов и приоритеты операций;
• операции нельзя переопределять для стандартных типов;
• операторы не могут иметь аргументов по умолчанию;
• операторы наследуются (за исключением оператора присваивания operator=);
• операторы не могут объявляться как static.
Оператор можно определить тремя способами:
• как метод класса;
• как дружественную функцию (материал следующей лекции);
• как обычную функцию.

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 15


Классы (оператор присваивания)
Операция присваивания определена в любом классе по умолчанию как поэлементное копирование. Эта операция
вызывается при всяком присваивании одного объекта в другой. Если объекты класса выделяют память
динамически, необходимо снабдить класс собственным оператором присваивания.
Для класса String оператор присваивания будет выглядеть следующим образом:
String& String::operator=(const String& st) {
if (&st==this) return *this; // Проверка на самоприсваивание.
if (_size!=st._size) {
delete [] _data;
_data=new char[(_size=st._size)+1];
}
strcpy(_data,st._data);
return *this;
}
Каждый объект класса имеет собственный экземпляр полей, но методы класса являются общими для всех
объектов. Константный указатель this – скрытый параметр, передаваемый методам класса – хранит адрес
объекта, вызвавшего метод (собственный адрес объекта).
Возврат ссылки на String из оператора присваивания делает возможной цепочки:
String st1(“Hello”),st2,st3;
st3=st2=st1;

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 16


Классы (оператор присваивания)
Класс String также должен иметь оператор присваивания от аргумента типа const char*:
String& String::operator=(const char* dt) {
int sz=strlen(dt);
if (_size!=sz) {
delete [] _data;
_data=new char[(_size=sz)+1];
}
strcpy(_data,dt);
return *this;
}
Таким образом, в конструкции:
String st1;
st1=“Hello”;
будет вызван лишь оператор operator=(const char*), а не пара String(const char*) и
operator=(const String&).

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 17


Классы (оператор индексирования)
Операция индексирования “[ ]” перегружается для классов, чьи объекты оперируют множеством
значений. Операция должна возвращать элемент или ссылку на него.
Класс String должен иметь оператор “[ ]” для чтения и записи символов:
char operator[](int i) const // Чтение символа.
{ if (i<0 || i>=size()) fatalMsg("Index out of range"); return _data[i]; }
char& operator[](int i) // Возврат ссылки позволяет изменять символ.
{ if (i<0 || i>=size()) fatalMsg("Index out of range"); return _data[i]; }

Оператор [] использует глобальную функцию аварийного завершения работы программы с печатью


диагностического сообщения:
void fatalMsg(const char* msg) { std::cout << msg << ‘\n’; abort(); }

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 18


Практическое задание
ЦЕЛЬ: применение теоретического материала на практике путем реализации класса String,
представленного перечисленными в лекции членами.
ХОД ВЫПОЛНЕНИЯ:
1. Реализовать класс String (конструкторы, деструктор, операторы присваивания и индексирования);
2. Снабдить методы класса отладочной печатью: к примеру, метод может печатать собственное имя. Таким
образом, обеспечивается возможность определить время и порядок вызова;
3. Выполнить функцию main(), проследив, какие методы String и в каком порядке будут вызваны:
String st1;
String st2("hello");
String st3="world";
String st4=st3;

for (int i=0; i<st2.size(); ++i) cout << st2[i]; cout << ‘\n’;
st2[3]='2';
for (int i=0; i<st2.size(); ++i) cout << st2[i]; cout << ‘\n’;
st2="Hast du etwas Zeit fur mich?";
for (int i=0; i<st2.size(); ++i) cout << st2[i]; cout << ‘\n’;

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 19


Список использованной литературы

1. Павловская Т. А. С/С++. Программирование на языке высокого уровня. СПб.:


Питер, 2004. 461 с.
2. Страуструп Б. Язык программирования C++: спец. изд. М.: Бином-Пресс, 2004.
1104 с.

КУРС "ОСНОВЫ ПРОГРАММИРОВАНИЯ" ОРЕХОВ М.Ю. 20

Вам также может понравиться