Лабораторная работа №12 / 12_классы_a5.doc
Лабораторная работа №12
Программирование на языке С++
с использованием классов.
Цель работы: 1) изучить возможности программирования классов на языке С++; 2) получить основные навыки программирования манипуляторов ввода/вывода.
Теоретические сведения
Класс есть расширение понятия структуры языка С++. Он позволяет создавать типы и определять функции, которые задают поведение типа. Каждый представитель класса называется объектом.
Определение класса
Определение класса идентично определению структуры в С++, за исключением того, что
оно обычно содержит одну или несколько спецификаций доступа (public, protected, private);
вместо ключевого слова struct используется слово class;
оно обычно включает в себя функции (функции-элементы или методы) наряду с данными-элементами;
обычно в нем имеются некоторые специальные функции, такие как конструктор (функция с тем же именем, что и сам класс) и деструктор (функция, именем которой является имя класса с префиксом - тильдой (~)).
Пример 12.1. Определение класса.
class str
{ char *s; //элемент-данное
public: //спецификатор открытого доступа
str(char *word); //функция-элемент: конструктор
~str(); //функция-элемент: деструктор
void write(); //функция-элемент: метод печати
};
Управление доступом
В С++ можно ограничить видимость данных и функций класса при помощи меток public, protected, private. Метка-спецификатор доступа применяется ко всем элементам класса, следующим за ней, пока не встретится другая метка или кончится определение класса.
Метка-спецификатор public (открытый) используется тогда, когда элементы-данные и функции-элементы класса должны быть доступны для функций-элементов и других функций программы, в которой имеется представитель класса.
Метка-спецификатор protected (защищенный) используется в том случае, когда элементы данных и функции-элементы должны быть доступны для функций-элементов данного класса и классов производных от него.
Метка-спецификатор private (закрытый) используется, если элементы-данные и функции-элементы должны быть доступны только для функций-элементов данного класса.
В классе элементы по умолчанию являются закрытыми.
Элементы класса
Элементы класса делятся на две основные категории:
данные, называемые элементами-данными;
код, называемый элементами-функциями или методами.
Данные-элементы
Данные-элементы классов С++ идентичны элементам структур языка С++ с некоторыми дополнениями:
данными-элементами могут быть перечислимые типы, битовые поля или представители ранее объявленного класса. Также допускается вложенное объявление перечислимого типа данных и создание псевдонимов с помощью typedef;
данное-элемент класса может быть указателем или ссылкой на представитель этого класса.
Элементы-функции
Функция-элемент является функцией, объявленной (описанной) внутри определения класса. Тело функции может также определяться внутри определения класса, в этом случае функция называется встроенной (inline) функцией-элементом. Когда тело функции определяется вне тела класса, перед именем функции ставится префикс из имени класса и операции разрешения видимости (::).
Пример 12.2.
class str
{ char *s; // указатель на строку
public:
str(char *word) // встроенный конструктор
{ s=new char[strlen(word)+1];
strcpy(s, word);
};
~str()
{ delete [ ]s; }; // встроенный деструктор
void write(); // объявление функции-элемента
};
void str::write() // определение функции-элемента
{ cout<<s);
};
Доступ к данным-элементам
Функции-элементы находятся в области действия класса, в котором они определены. Т.о. они могут обращаться к любому элементу класса, используя просто имя переменной. Обычные функции или функции-элементы другого класса могут получить доступ к элементам-данным с помощью операции . или −>, применяемых к представителю или указателю на представитель класса.
Пример 12.3.
class coord
{ public: int x, y; // координаты x и y
};
void main()
{ coord org; // представитель класса координат
coord *orgptr = &org; // указатель на представитель класса
org.x = 0; // задание значения координаты x
orgptr−>y = 0; // задание значения координаты y
}
Вызов функций-элементов
Функции-элементы класса могут вызывать другие функции-элементы того же класса, используя имя функции.
Пример 12.4.
class coord
{ int x, y; // координаты x и y
public:
void setcoord(int _x, int _y)
// функция задания значений координат
{ x =_x; y =_y;
};
void getcoord(int &_x, int &_y)
//функция получения значений координат
{_x = x; _y = y;};
};
void main()
{ coord org; // представитель класса координат
coord *orgptr = &org; // указатель на представитель класса
org.setcoord(10, 10); // вызов функции-элемента
// задания значений
int col, row;
orgptr−>getcoord(col, row); // вызов функции-элемента
// получения значений координат
}
Указатель this
Каждая нестатическая (не имеющая спецификатора static) функция-элемент имеет доступ к объекту, для которого вызвана, через ключевое слово this. Указатель this является указателем на тип_класса *.
Пример 12.5.
class simple
{ public:
simple();
void greet() { cout<<“ Hello!”;};
};
simple::simple()
{ greet(); // вызов
this−>greet(); // функции
(*this).greet(); // greet()
}
Т.к. функции-элементы могут обращаться ко всем элементам класса просто по имени, в основном указатель this используется для возвращения указателя (return this) или ссылки (return *this) на подразумеваемый объект.
Конструктор
Конструктор инициализирует представитель класса (объект) и является функцией-элементом с тем же именем, что и класс. Конструктор вызывается компилятором всегда, когда создается представитель класса. Объект считается созданным в тот момент, когда завершил работу конструктор объекта.
Для конструкторов выполняются следующие правила:
для конструктора не указывается возвращаемый тип;
конструктор не может возвращать значение;
конструктор не наследуется;
для одного класса может существовать один или несколько конструкторов;
если конструктор не задан явным образом, то автоматически создаётся пустой конструктор.
Деструктор
Деструктор является дополнением конструктора. Он имеет то же имя, что и класс, но с префиксом - тильдой (~). Он вызывается всякий раз, когда уничтожается представитель класса. Объект считается уничтоженным, когда завершил работу деструктор объекта. Для деструктора существуют следующие правила:
деструктор не может иметь аргументов;
деструктор не может возвращать значения;
деструктор не наследуется (исключением является виртуальный деструктор);
для одного класса может существовать только один деструктор;
если деструктор не задан явным образом, то автоматически создаётся пустой деструктор.
Пример 12.6.
//file ctime.h
#ifndef __CTIME_H__
#define __CTIME_H__
class CTime
{ char *timestr;
public:
CTime(char *str=”00:00:00”); //конструктор по умолчанию
CTime(const CTime& clk); //копирующий конструктор
~CTime(); //деструктор
show(); //функция-элемент
}; //обязательно ставить точку с запятой, т.к. class -
// объявление типа
#endif
//file ctime.cpp
#include <string.h>
#include <iostream.h>
#include “ctime.h”
CTime:: CTime(char *str=”00:00:00”)
{ timestr=new char[strlen(str)+1];
strcpy(timestr,str);
}
CTime:: CTime(const time& clk)
{ timestr=new char[strlen(clk.timestr)+1];
strcpy(timestr,clk.timestr);
}
CTime::~ CTime()
{ delete [] timestr;
}
CTime::show()
{ cout<<”Time is “<<timestr<<endl;
}
//file main.cpp
#include “ctime.h”
void main(void)
{ CTime a; //для а вызывается конструктор по умолчанию
CTime *b=new CTime; //для b вызывается конструктор по
// умолчанию
CTime e(a); //для e вызывается копирующий конструктор
//вызовем функцию-элемент
a.show(); //00:00:00
b->show(); //00:00:00
e,show; //00:00:00
}
//в конце области видимости автоматически вызываются деструкторы объектов в порядке, обратном вызову конструкторов, т.е. сначала для е, затем для d и т.д..
Форматируемый ввод/вывод. Манипуляторы.
При вводе/выводе данных можно воспользоваться манипуляторами, то есть специальными функциями форматирования, которые могут находиться в теле оператора ввода/вывода. Если в манипуляторе используются параметры, то необходимо подключение заголовочного файла <iomanip.h>.
Для сохранения и восстановления состояния потока используется функция-метод класса потока flags(). Например:
long a;
a=cout.flags(); //для сохранения состояния потока в а
cout.flags(a); //для восстановления состояния потока из а
Таблица 12.1
Манипуляторы ввода/вывода.
Манипулятор | Назначение | Ввод/вывод |
dec | Вывод числовых данных в десятичной системе счисления. | Вывод |
hex | Вывод числовых данных в шестнадцатеричной системе счисления. | Вывод |
Манипулятор | Назначение | Ввод/вывод |
oct | Вывод числовых данных в восьмеричной системе счисления. | Вывод |
endl | Вывод символа новой строки и флэширование. | Вывод |
ends | Вывод нуля (NULL). | Вывод |
flush | Флэширование. | Вывод |
ws | Пропуск начальных пробелов. | Ввод |
resetiosflags(long f) | Сброс флагов, задаваемых в f. | Ввод/вывод |
setbase(int основание) | Устанавливает основание системы счисления для вывода данных. | Вывод |
setfill(char ch) | Устанавливает символ заполнения ch. | Вывод |
setiosflags(long f) | Установка флагов, задаваемых в f. | Вывод |
setprecision(int p) | Задает число символов после десятичной точки, равным p. | Вывод |
setw(int w) | Задает ширину поля, равной w позиций. | Вывод |
Примеры программирования
Пример 12.7. Вывод данных с использованием манипуляторов.
#include <iostream.h>
#include <iomanip.h>
#include <math.h>
int main()
{ double x, y;
cout << "Input x ";
cin >> x;
y = sin(x);
cout << setprecision(3);
cout << setw(7) << x;
cout << setw(7) << y;
return 0;
}
Пример 12.8. Описать и определить класс-список.
Файл list.h содержит описание класса.
#ifndef __LIST_H__
#define __LIST_H__
struct list
{
int inf; // информационное поле
list *next; // указатель на следующий элемент списка
};
class CSpisok
{
list* head; // указатель на начало списка
public:
CSpisok (int);
CSpisok (CSpisok&);
void print ();
~CSpisok();
};
#endif
Файл list.cpp содержит определение функций-элементов.
#include <stdlib.h>
#include <iostream.h>
#include <iomanip.h>
#include "list.h"
CSpisok:: CSpisok(int n)
//конструктор инициализирует список из n элементов по принципу
// "очередь"
{ head = NULL;
list *p,*pn;
for (int i = 0; i<n; i++)
{
p = new list;
p−>inf = random(100)-50;
p−>next = NULL;
if (head == NULL) head = p;
else pn−>next = p;
pn = p;
}
}
CSpisok:: CSpisok (const CSpisok& s)
//конструктор копии класса CSpisok
{ head = NULL;
list *sp = s.head, *p, *pn;
while (sp)
` { p = new list;
p−>inf = sp−>inf;
p−>next = NULL;
if (head == NULL) head = p;
else pn−>next = p;
pn = p;
sp = sp−>next;
}
}
CSpisok::~ CSpisok()
//деструктор - уничтожает объект класса список из памяти
{ list *p;
while (head)
{ p = head;
head = head−>next;
delete p;
}
}
void CSpisok::print()
//функция-элемент печати содержимого списка
{ list *p = head;
while (p)
{ cout<<setw(5)<<p−>inf;
p = p−>next;
}
cout<<endl;
}
Файл main.cpp содержит основную функцию.
#include <iostream.h>
#include <iomanip.h>
#include “list.h”
void main (void)
{ spisok s1(10), // создание списка из 10 элементов
s2(s1), // s2- копия списка s1
s3(15); // создание списка из 15 элементов
s1.print(); // печать s1
s2.print(); // печать s2
s3.print(); // печать s3
}
В проект включены файлы: main.cpp и list.cpp.
Результаты выполнения программы:
-49 -50 -17 -47 -15 -29 3 -31 20 44
-49 -50 -17 -47 -15 -29 3 -31 20 44
-23 -6 -40 19 6 -46 -34 31 18 26 32 45 -29 -8 45
Контрольные вопросы
Что представляет собой класс?
Какие спецификации доступа используются при описании класса?
Что является элементами класса?
Как осуществляется доступ к элементам класса?
Для чего используется указатель this?
Что такое конструктор?
Что такое деструктор?
Порядок выполнения лабораторной работы
Напишите программу согласно Вашему варианту задания.
Варианты заданий
Номер | Задание |
1, 14 | Определить класс-строку. В класс включить два конструктора: для определения класса строки строкой символов и путем копирования другой строки (объекта класса строки). Предусмотреть функции поиска слова в строке и добавления другой строки, начиная с позиции N |
Номер | Задание |
2, 15 | Определить класс-строку. В класс включить два конструктора: для определения класса строки строкой символов и путем копирования другой строки (объекта класса строки). Предусмотреть функции слияния двух строк и функцию подсчёта предложений в строке. |
3, 16 | Определить класс-строку. В класс включить два конструктора: для определения класса строки строкой символов и путем копирования другой строки (объекта класса строки). Предусмотреть функции сортировки слов в строке по-алфавиту и подсчёта количества слов. |
4, 17 | Определить класс список элементов. В определение класса включить два конструктора: для определения списка по его размеру и путем копирования другого списка. Предусмотреть функции подсчёта количества элементов списка и добавления одного списка в другой список, начиная с позиции N. |
