- •Введение. Принципы объектно-ориентированного программирования
- •Глава 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. Библиотека стандартных шаблонов (бсш). Контейнеры
12. Член-данные класса – объекты другого класса: агрегированные классы.
Член-данное какого-либо класса может быть переменной, указателем или ссылкой, тип которых – другой известный на данный момент класс. Такой класс называется агрегированным.
Рассмотрим пример.
class A
{ int x, y;
public:
A(int xx = 0) {x = y = xx;} // конструктор с аргументом по умолчанию
A(int xx, int yy) {x = xx; y = yy;}
void Print( ) {cout << ’\n’ << x << ’ ‘ << y;}
int Getx( ) {return x;}
int Gety( ) {return y;}
};
class B // агрегированный класс
{A a;
int z;
public:
B( ) {z = 0;}
B(int, int, int ) ;
void Print( );
…
};
Главное правило при использовании объектов другого класса: конструктор использующего класса отвечает за инициалаизацию член-данных используемых классов!
В нашем примере – это конструктор класса B. И этот конструктор должен быть задан так:
B:: B(int, int, int ): a(b, c), z(d) { }
список инизиализации
Собственные член-данные можно инициализировать и внутри { }:
B:: B(int b, int c, int d): a(b, c) {z = d;}
Заметим, что если в классе A есть конструктор по умолчанию, то он будет работать, даже если он явно не указан в списке инициализации конструктора класса B. В нашем примере при работе конструктора B( ) будет работать конструктор A(int xx = 0).
Порядок работы конструкторов при объявлении объекта класса B: сначала в A, затем в B.
Несколько сложнее выглядит конструктор агрегированного класса, если член-данное в нем – указатель на объект другого класса, и он определяет массив. В этом случае конструктор должен брать память в динамической области и инициализировать элементы массива. Списком инициализации здесь не обойтись. Рассмотрим на примере, как в этом случае можно определить конструктор агрегированного класса.
Пусть имеется класс Array – числовой массив. Используем его для определения класса числовая матрица Matrix:
class Matrix
{Array * a; int m, n;
public:
Matrix(int m1, int n1, int t = 0); // t != 0 – создание элементов матрицы случайным образом
Array &operator [ ](int i) // возвращает ссылку на i-ую строку матрицы
{if (i < 0 || i >= m) {cout << ”Такой строки нет!”); exit(0);}
return a[i];
}
void Show( ); // вывод матрицы
...
};
Matrix:: Matrix(int m1, int n1, int t)
{a = new Array[m = m1]; // Так как в этом случае используется только конструктор по умолчанию
// класса Array (см п.10), то определить строки длиной n можно таким образом:
n = n1;
for(int i = 0; i < m; i++)
{Array b(n, t); // создается массив – строка матрицы, t – инициализация
a[i] = b; // работает перегруженная операция ‘=’ класса Array
}
}
Пример использования:
void main( )
{Matrix c(4, 5, 1);
c.Show( );
c[1][1] = 100; // Работают две перегруженные операции [ ]: первая – в классе Matrix, вторая – в классе Array
cout << c[0]; // вывод строки с номером 0 операцией потокового вывода, определенной для класса Array
}
Вернемся к классам A и B.
Разберемся, как в классе B можно использовать член-данные х и у из класса A. Определим функцию вывода в классе B:
void B:: Print( ) {cout << ’\n’ << a.x << ‘ ’ << a.y << ’ ‘ << z;} (1)
Так нельзя! a.x, a.y – член-данные из части private класса A
Способы выхода из положения:
использовать a.x и a.y в член-функциях класса B непосредственно станет возможным (см. (1)), если объявить класс B дружественным классу A.
class B;
class A {friend class B;
...
};
использовать x и y через член-функции класса A из части public:
void B:: Print( ) {a.Print( ); cout << ’ ‘ << z;}
в некоторых случаях приходится специально задавать функции, которые возвращают то или иное значение из части private используемого класса. Например, в классе A – функции Getx( ), Gety( ). Функция Print( ) в классе B в этом случае может быть определена таким образом
void B:: Print( ) {cout << ’\n’ << a.Getx( ) << ’ ‘ << a.Gety( ) << ’ ‘ << z;}
Пример использования агрегированных классов.
void main( )
{ A a1, a2(7, 8); // работают оба конструктора класса A
B b1; // работают конструкторы по умолчанию классов A и B:
// b1.a.x = b1.a.y = b1.z = 0;
B b2(1, 2, 3); // работают конструкторы с аргументом сначала A,
// потом B: b2.a.x = 1; b2.a.y = 2; b2.z = 3;
a1.Print( ); a2.Print( ); // функция Print( ) класса A
b1.Print( ); b2.Print( ); // функция Print( ) класса B
}
Рассмотрим графический пример.
Зададим 3 класса: прямоугольник Bar, круг Circ, круг на прямоугольнике CircOnBar.
const int CF = 7;
class Bar
{ int h, w, x, y;
public:
Bar(int hh, int ww, int xx, int yy)
{h = hh; w = ww; x = xx; y = yy;}
void Show(int c) { };
};
class Circ
{int r, x, y;
public:
Circ(int rr, int xx, int yy) {r = rr; x = xx; y = yy;}
void Show(int c) { }
};
class CircOnBar
{ Bar b;
Circ c;
public:
CircOnBar(int h, int w, int x, int y, int r): b(h, w, x, y), c(r, x + w / 2, y - r) { }
void Show(int cb, int cc)
{b.Show(cb); c.Show(cc);}
};
void main( )
{ int x = 20, i, dx = 100;
// Определяем массив агрегированных объектов - CircOnBar
CircOnBar bc[3] = {CircOnBar(100, 50, x = x + dx, 100, 30),
CircOnBar(100, 50, x = x + dx, 100, 30),
CircOnBar(100, 50, x + dx, 100, 30)};
for(i = 0; i < 3; i++)
bc[i].Show(2 * i + 1, 2 *i + 2); //Выводим их на экран
CircOnBar * pbc = new CircOnBar(50, 50, 500, 300, 50); // Объект в динамической памяти:
pbc –> Show(4, 12);
delete pbc;
}
