- •Введение. Принципы объектно-ориентированного программирования
- •Глава 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. Библиотека стандартных шаблонов (бсш). Контейнеры
5. Неявный указатель this
Каждый объект класса имеет свою копию член-данных и один экземпляр каждой член-функции для всех объектов. Возникает вопрос, как же член-функция “понимает”, с член-данными какого объекта она работает? Ответ очевиден – с теми, которые принадлежат объекту, вызвавшему эту функцию.
Например,
s2.Print();
Говорят, что в функцию в этом случае передается неявный указатель на этот объект. Его можно задать и явно с помощью ключевого слова this.
Например,
void Print() {cout << this –> line;}
Однако в данном случае это излишне. Но бывают ситуации (кстати, довольно часто при использовании ООП), когда приходится задавать этот указатель явно.
Например, в классе String определим функцию, которая будет к первой строке приписывать вторую и результатом возвращать первую (конкатенация строк), объявив ее в классе
String Plus(String &);
и определив ее за классом:
String String :: Plus(String &s2)
{char *t = new char[len + 1];
strcpy(t, s.line); delete [ ]line;
len += s2.len; line = new char[len + 1];
strcpy(line, t); strcat(line, s2.line);
delete [ ] t;
return *this; // возвращаем “этот” объект
}
Пример использования этой функуции:
String s1(“Объект “), s2(“класса String.”);
String * s3 = new String(s1.Plus(s2));// работает функция Plus( ), а затем конструктор копирования
s3 –> Print(); // вывод *s3 = ”Объект класса String.”;
6. Перегрузка операций
В С++ можно выполнить перегрузку операций для объектов класса, то есть с помощью знаков операций +, -, * и так далее можно определить похожие действия для абстрактных типов данных.
Формат перегрузки двуместной операции имеет вид
тип_возвращаемого_значения operator @ (операнд_2)
{тело_операции},
где @ – знак операции.
Первым операндом является объект, с которым эта операция вызывается, то есть * this, второй операнд – произвольный.
Используется перегруженный знак так же, как для стандартных типов данных
операнд1 @ операнд2
В классе String вместо функции Plus( ) можно определить операцию ‘+=’.
String& String:: operator +=(String & s2)
{char *t = new char[len + 1];
strcpy(t, line); delete [ ]line;
len += s2.len; line = new char[len + 1];
strcpy(line, t); strcat(line, s2.line);
delete [ ] t;
return *this;
}
Тогда в примере из п.5 вместо оператора
String *s3 = new String(s1.Plus(s2));
можно записать
String *s3 = new String(s1 += s2);
И еще пример использования.
String s(«Студент »), r(«Петров »);
s += r; // s = «Студент Петров»
В классе String определим функцию сравнения двух строк.
int String:: EqStr(String &s)
{if (strcmp(line, s.line)) return 0; // строки не равны
return 1; // строки равны
}
Использовать ее можно так.
String s1(“Иванов”), s2(“Петров”);
if (s1.EqStr(s2)) cout << ”Строки равны”;
else cout << ”Строки не равны”;
Но было бы нагляднее для сравнения строк использовать операцию = =. Перегрузим ее для класса String.
int String:: operator = =(String & s)
{ if (strcmp(line, s.line)) return 0; // также как и в функции EqStr( )
return 1;
}
Cравнение теперь выглядит привычнее:
if (s1== s2) cout << ”\n Строки равны”;
else {s1.Print( ); cout << ” – это не “;s2.Print( );} //”Иванов – это не Петров”
Формат перегрузки одноместной операции имеет вид
тип_возвращаемого_значения operator @(пусто)
{тело_операции},
где @ – знак операции.
Напишем в качестве примера операцию реверса строки, т.е. перестановки символов в обратном порядке.
String String:: operator ~( )
{int i; char t;
for(i = 0; i < len / 2; i++)
t = line[i], line[i] = line[len – i –1], line[len – i – 1] = t;
return *this;
}
С помощью двух этих операций решим задачу: является ли слово «перевертышем».
void main( )
{String s1(“шалаш”);
String s2 = s1; // Работает конструктор копирования
s1.Print( );
if (s1 == ~s2) cout << ” – перевертыш”;
else cout << ” – не перевертыш”;
}
Правила перегрузки:
При перегрузке операции, как член-функции класса, двуместная операция имеет один аргумент, одноместная – ни одного;
Знак одноместной операции может быть перегружен только как одноместный, а двуместной – только как двуместный;
Наряду с обычным использованием перегруженного знака
obj1 @ obj2 для двуместной
и
@ obj для одноместной
он может использоваться как член-функция класса
obj1.operator @(obj2)
и
obj.operator @()
Нельзя перегружать операции для стандартных типов данных. Например, + для массивов, определенных, как int * a или int a[20].
Нельзя перегружать операции
:: . ?: sizeof
