- •Введение. Принципы объектно-ориентированного программирования
- •Глава 1. Классы и объекты
- •1.1. Операция разрешения области видимости ::
- •1.2. Перечислимый тип
- •1.3. Модификатор const
- •1.4. Новый тип данных – ссылка &
- •Inline определение_функции
- •2. Определение класса. Сокрытие информации.
- •3. Объект.
- •4. Конструкторы и деструкторы
- •4.1.Назначение конструктора
- •4.2. Конструктор копирования
- •X::X(X&); // где X – имя класса
- •4.3. Деструктор
- •5. Неявный указатель this
- •6. Перегрузка операций
- •7. Примеры перегрузки некоторых операций
- •7.1. Перегрузка операции [ ]
- •7.2. Перегрузка операции ()
- •7.6. Перегрузка операции (тип)
- •8. Дружественность
- •Istream
- •10. Массивы объектов.
- •11. Функции- и классы-шаблоны
- •11.1 Функции-шаблоны (родовые функции)
- •11.2 Классы-шаблоны
- •12. Член-данные класса – объекты другого класса: агрегированные классы.
- •Глава 2. Наследование. Полиморфизм
- •1. Базовый и порожденный классы
- •2. Конструкторы порожденного класса
- •3. Стандартные преобразования при наследовании
- •4. Множественное наследование. Виртуальный базовый класс
- •4.1. Прямые базовые классы
- •4.2. Виртуальный базовый класс
- •5. Полиморфизм, раннее и позднее связывание, виртуальные функции
- •5.1 Раннее (статическое) и позднее (динамическое) связывание
- •5.2. Определение виртуальной функции
- •5.3. Чистая виртуальная функция и абстрактный класс
- •5.4. Правила определения виртуальных функций
- •5.5. Механизм позднего связывания
- •6. Библиотека fstream – работа с файлами
- •Глава 3. Библиотека стандартных шаблонов (бсш). Контейнеры
- •1. Контейнер. Структура бсш.
- •2. Контейнер Vector – динамический массив
- •Контейнер list – список
- •4. Контейнер Set – множество
- •Содержание
- •Глава 1. Классы и объекты
- •Глава 2. Наследование. Полиморфизм
- •Глава 3. Библиотека стандартных шаблонов (бсш). Контейнеры
3. Объект.
Класс – это тип данных, а не объект.
Определение. Объект – это переменная, тип которой – класс, и определяется он обычным образом.
void main()
{String s1, s2, *s3; // s1, s2 – объекты, s3 – указатель на объект.
…
}
Говорят также, что s1, s2 – экземпляры класса. Для каждого из них отведена будет память по 255 + 4 байтов.
Заметим, что указатель s3 пока не определен, т.е. там грязь.
Посмотрим, как мы теперь можем работать с объектами.
s1.Fill(“объект”);
s2.Fill(“ класса String ”);
s1[0] = ’O’; // ошибка: s1 – это не массив, и операция [] в нем не определена!
s1.line[0] = ‘O’; // опять ошибка: line – приватное ч/данное, в main использовать нельзя!
s1.Index(0) = ‘О’; // Это верно – пока только так, через ч/функцию, можно «добраться» до символа строки
cout << s1.len; // ошибка: len – приватное член-данное
cout << s1.Length(); // так можно получить длину строки
s3 = &s1; // s3 – указатель на строку s1
s3 –> Index(0) = ‘O’; // используя функцию Index(int), заменим еще раз букву ‘о’ на ’О’
s3 –> Print(); // вывод слова «Объект»
s3 = &s2; // теперь s3 – указатель на объект s2
s3 –> Index(s3 –> Length() - 1) = ‘.’; // Используя член-функции класса Length() и Index()
// поставим в конце строки s3 символ '.'
s3 –> Print(); // вывод фразы « класса String.»
s3 = new String(«Динамическая память»); // определяется объект в динамической памяти
4. Конструкторы и деструкторы
4.1.Назначение конструктора
В С++ при определении переменных часто их сразу инициализируют, например,
int x = 5;
Предположим, что при определении объекта
String s;
мы хотели бы проинициализировать его, например, пустой строкой:
len = 0; line[0] = ’\0’.
Для структур эта инициализация выполняется так:
String s = {“”, 0};
Для объектов класса такая инициализация запрещена в силу принципа инкапсуляции.
Поэтому и возникает проблема: внутри описания класса инициализировать нельзя по синтаксису языка, но и вне класса записать
s.len = 0; s.line[0] = ’\0’;
тоже нельзя, т.к. член-данные из части private недоступны. (Заметим, что если определить их в части public, то их можно инициализировать таким образом
String s = {«», 0};
то есть как структуру)
Следовательно, инициализацию должна выполнять специальная член-функция класса.
Определение. Член-функция класса, предназначенная для инициализации член-данных класса при определении объектов класса, называется конструктором. Конструктор всегда имеет имя класса.
Для решения нашей задачи можно записать такой конструктор
Strring:: String( ) { len = 0; line[0] = ’\0’;} (1)
объявив его обязательно в теле класса следующим образом:
String( );
Тогда при определении объектов, например,
String s1, s2;
он будет всегда вызываться неявно, и выполнять инициализацию объектов. Так как конструктор не имеет аргументов, то он называется конструктором по умолчанию.
В классе можно задать не один конструктор, а несколько. Для класса String можно задать конструктор с аргументом, аналогичный функции Fill( ).
String:: String(const char * s)
{for(len = 0; line[len] != ‘\0’; line[len] = s[len], len++);
line[len] = ‘\0’;}
Тогда объекты можно определить таким образом:
String s1, s2(«Иванов»), *s3 = new String(«Петров»);
В последнем случае конструктор задается явно. Заметим, что в классе должен быть один конструктор по умолчанию и один или несколько с аргументами.
Особенности конструктора, как функции:
Главная – конструктор не имеет возвращаемого значения (даже void), так как его назначение – инициализировать собственные член-данные объекта;
Конструктор имеет имя класса;
Конструктор работает неявно при определении объектов класса.
Недостаток определенного класса String – это то, что он берет для каждого объекта 257 байтов памяти, хотя фактически использует меньше.
Изменим определение класса String таким образом:
class String { char *line; int len;
public:
....
}
;
В этом случае конструкторы надо определить иначе, т.к. кроме инициализации значений член-данных, они должны брать память в динамической области для поля line.
Зададим такие конструкторы.
В классе объявим 2 конструктора:
String(int I = 80); // с аргументом по умолчанию
String(const char *); // с аргументом строкой
и определим их вне класса
String:: String(int l) // l = 80 – не повторять! (2)
{line = new char[l]; len = 0;
line[0] = ’\0’;
}
String:: String(const char * s)
{line = new char [strlen(s) + 1];
for(len = 0; line[len] != ‘\0’; line[len] = s[len], len++);
line[len] = ‘\0’;
}
Эти конструкторы можно использовать таким образом:
String s1(10), s2, s3(«без слов»);
Заметим, что в классе должен быть или конструктор по умолчанию без аргументов (вида (1)), или конструктор по умолчанию с аргументом по умолчанию (вида (2)). В противном случае, следующее определение:
String ss;
вызовет сообщение о двусмысленности.
