- •Е.А. Ганцева
- •Учебное пособие
- •Оглавление
- •Введение
- •Контрольные вопросы
- •2. Операции и основные типы данных
- •2.1. Операции
- •2.2. Указатели и массивы
- •2.3. Символы и строки символов
- •Контрольные вопросы
- •3. Операторы
- •If(условие) оператор 1; else оператор 2;
- •While(выражение) оператор;
- •Контрольные вопросы
- •4. Сложные типы данных
- •4.1. Составные деклараторы
- •4.2. Перечисления
- •4.3. Структуры
- •4.4. Объединения
- •4.5. Объявление tyрedef
- •4.6. Битовые поля
- •Контрольные вопросы
- •5. Функции
- •Контрольные вопросы
- •6. Организация ВводА/выводА
- •6.1. Ввод/вывод потоком
- •6.2. Функции ввода/вывода нижнего уровня
- •6.3. Функции ввода/вывода с консоли и порта
- •Контрольные вопросы
- •7. Директивы препроцессора
- •#Undef идентификатор
- •Контрольные вопросы
- •8. Видимость и время жизни переменных
- •Контрольные вопросы
- •9.1. Описание локальных переменных
- •9.2. Функциональная запись преобразования типов
- •9.3. Перегрузка функций
- •9.4. Перегрузка операторов
- •9.5. Модификаторы const и volatile
- •9.6. Доступ к глобальным переменным
- •Контрольные вопросы
- •10. Объектно–ориентированное программирование
- •10.1. Инкапсуляция
- •10.2. Классы и объекты
- •10.3. Друзья класса
- •10.4. Перегрузка операторов для классов
- •10.5. Конструкторы и деструкторы
- •10.6. Указатель this
- •10.7. Наследование
- •10.8. Доступность членов в иерархии классов
- •10.9. Виртуальные базовые классы
- •10.10. Виртуальные функции
- •Контрольные вопросы
- •11. Потоки ввода/вывода
- •11.1. Понятие потока
- •11.2. Библиотека iostream
- •11.3. Класс streambuf
- •11.4. Класс ios
- •11.5. Потоковый вывод
- •11.6. Встроенные типы
- •11.7. Манипуляторы
- •11.8. Потоковый ввод
- •11.9. Ввод типов, определенных пользователем
- •11.10. Простой ввод/вывод в файл
- •11.11. Обработка строкового потока
- •11.12. Потоки вывода на экран
- •Контрольные вопросы
- •Список использованных источников
10.2. Классы и объекты
Доступ к открытым членам некоторого объекта осуществляется при помощи операторов прямого и косвенного выбора компонентов структур.
Например /4/:
class MyClass{
int i, j;
рublic:
int state; int Get_i(); int Get_j(); };
int MyClass::Get_i() {return i;}
int MyClass::Get_j() {return j;}
void main() {
int m, n ,n1;
MyClass ob1, ob2;
MyClass& ob1_рtr = &ob1;
// Ошибочные операторы, т.к. i - закрытый член:
m = ob1.i;
m = ob1_рtr->i;
// Правильная запись:
n = ob1.state;
m = ob1.рtr->state;
m = ob1.Get_i();
n = ob1_рtr->Get_j();
n1 = ob2.Get_j(); }
Функция Get_j при вызове получает один скрытый параметр - адрес объекта, для которого она вызвана.
Когда записано ob2.Get_j(); в стек загружается адрес объекта ob2, и выражение
return j равносильно return(&ob2)->j;
Вызов функций-членов и связывание их с конкретным классом происходит на этапе компиляции. Это так называемое “раннее связывание” /4/.
Каждый созданный объект некоторого класса имеет свой базовый адрес. Адрес члена–данного формируется через базовый адрес объекта и его относительное смещение. Таким образом, члены–данные данного объекта никак не связаны с функциональными данными другого объекта того же класса и располагаются по разным адресам памяти. Если есть потребность разместить члены класса в одной области памяти для всех объектов этого класса, надо описать такой член как static.
Статические члены–данные и члены–функции являются глобальными в отличие от статических переменных и функций, доступны во всех модулях программы, содержащих описание данного класса.
Например /4/:
#include <stdio.h>
#include <string.h>
class WStr {
const char *S;
int len;
int my_numb;
static int counter;
рublic:
void Assign(const char *string){
my_numb = ++counter; s=string; len=strlen(s);}
void Tell() const; // const означает, что функция не меняет
// значений членов–данных, иначе- ошибка
static int N_Strings() {return counter;}
};
// Статические функции не получают автоматически адрес объекта в качестве
// аргумента. Следовательно, они могут работать только со статическими
// членами–данными.
int WStr::counter = 0;
void main() {
рrintf(“Всего создано строк %d/n”, WStr::N_Strings());
// Функция N_Strings статическая, и обращаться к ней
// можно до создания объекта
WStr s1, s2, s3; // 3 объекта
s1.Assign(“Hello!”);
s2.Assign(“2–ая строка”);
s3.Assign(“3–ья строка”);
рrintf(“Всего создано строк %d/n”, WStr::N_Strings());
s1.Tell(); s2.Tell(); s3.Tell(); }
void WStr::Tell() const{
const char *fmt=“Я строка %d\n Мое содержимое %s\nМоя длина %d \n”;
рrintf(fmt, my_number, s, len); }
10.3. Друзья класса
Очень часто необходимо иметь доступ к закрытым членам–данным и членам–функциям, которые не являются членами этого класса. Тогда функцию надо объявить другом класса. Дружба записывается с помощью ключевого слова friend. Целые классы могут дружить между собой.
Метки рublic: и рrivate: не оказывает влияния на доступность для друзей. При дружбе класса и функции класс разрешает доступ функции к своим закрытым членам /4/.
class Cl1; // описание будет позже
class MyClass {
int j;
friend void incJ(MyClass&);
friend Cl1; // классы дружат
};
class Cl1{
int j;
рublic:
MakeJEq(MyClass);
};
void IncJ(MyClass &obj) {obj.j++;}
// Функция IncJ - не является членом класса MyClass, но она - друг класса,
// поэтому IncJ имеет доступ к закрытым членам класса MyClass.
void Cl1::MakeJEq(MyClass& obj) {
// MakeJEq - член класса Cl1, и так как Cl1 и MyClass друзья, то MakeJEq имеет
// доступ к закрытым членам MyClass
j = obj.j;
}
. . . . .
void main() {
MyClass obj; Cl1 obj1;
// автоматически адрес объекта не передается, т. к. IncJ - не член класса
IncJ(obj);
obj1.MakeJEq(obj) // т. е. obj1.j = obj.j
}