
- •220300 - Системы автоматизированного проектирования
- •Тема 2. Технологии программирования
- •Тема 2. Технология разработки крупных приложений
- •Структуры
- •Структуры и функции
- •Массивы структур
- •Поиск в массиве структур
- •Вложенность структур
- •Рекурсия
- •Алгоритм быстрой сортировки
- •Массивы структур и бинарные файлы
- •Динамические структуры данных
- •Линейные списки
- •Очереди
- •Контрольная работа
- •Объектно-ориентированное программирование. Классы
- •Конструкторы
- •Перегруженные конструкторы
- •Определение методов класса вне класса
- •Объекты, возвращаемые функцией (методом)
- •Структуры и классы
- •Классы и память
- •Статические данные класса
- •Константные методы
- •Деструкторы
- •Массивы и классы
- •Массивы объектов
- •Строки Строковый тип или стандартный класс string
- •Тип строк AnsiString
- •Перегрузка операций
- •Перегрузка арифметических операций
- •Перегрузка операций сравнения
- •Перегрузка операции приведения типа
- •Преобразования объектов в основные типы и наоборот
- •Преобразование объектов классов в объекты других классов
- •Наследование
- •Конструкторы производного класса
- •Перегрузка функций
- •Иерархия классов
- •Общее и частное наследование. Комбинации доступа
- •Множественное наследование
- •Включение. Классы в классах
- •Виртуальные и дружественные функции
- •Абстрактные классы и чистые виртуальные функции
- •Виртуальные деструкторы
- •Виртуальные базовые классы или устранение неоднозначности при множественном наследовании
- •Дружественные функции
- •Дружественные классы
- •Указатель this
- •Многофайловые программы
- •Распознавание нажатых клавиш
Массивы и классы
На примере класса Tovar мы уже видели, что массивы могут быть использованы в качестве полей класса. Рассмотрим пример класса, который моделирует структуру данных – стек.
class Stack {
private:
static const int MAX=5;
int st[MAX]; // стек в виде массива
int top; // вершина стека
public:
Stack( ) { top = 0; }
void push(int a) { // поместить в стек
st[top] = a;
if(top < MAX-1) top++;
}
int pop( ) { // взять из стека
int res=st[top];
top--;
return res;
}
int max() { return MAX; }
};
//---------------------------------------------------------------------------
int main ( ) {
Stack s1;
int i;
for(i=1; i<=s1.max(); i++) s1.push(i);
for(i=0; i<s1.max(); i++) cout << s1.pop() << endl;
getch(); return 0;
}
Важным членом этого класса является массив st. Переменная top хранит индекс последнего элемента, положенного в стек. Этот элемент располагается на вершине стека.
Стандарт С++ позволяет объявлять константы внутри класса. Таким образом вместо строки enum { MAX = 5 }; мы использовали запись static const int MAX = 5; , но имейте ввиду, что некоторые компиляторы (в отличие от С++Builder) не позволяют использовать эту конструкцию.
Рассмотрим принцип работы программы. При добавлении в стек нового элемента индекс переменной top увеличивается, и она будет показывать на новую вершину стека. При извлечении (удалении) элемента из стека индекс переменной top уменьшается. В данном случае не нужно стирать старое значение из памяти при удалении элемента, оно просто становится несущественным.
Массивы объектов
На прошлых занятиях мы часто разбирали примеры класса Distance, который объединял футы и дюймы в своём объекте, представляющий собой новый тип данных. На следующем примере продемонстрируем массив таких объектов.
class Distance { //класс англиских мер длины
private:
int feet;
float inch;
public:
void getdist() { //получение информации при вводе
cout << "\nVvedi futy: "; cin >> feet;
cout << "Vvedi duimy: "; cin >> inch;
}
void showdist() const { //вывод информации
cout << feet << "'-" << inch << endl;
}
};
//------------------------------------------------------------------
int main() {
const int MAX = 100;
Distance dist[MAX]; //массив объекта
int n=0; //сч¸тчик данных
char ans; //ответ пользователя ('y' или 'n')
do {
cout << "Vvod dliny N " << n+1;
dist[n].getdist();
n++;
cout << "\nProdol. vvod (y/n)?: "; cin >> ans;
}while(ans == 'y' && n<MAX);
for(int j=0; j<n; j++) { //показать все введ¸нные значения длин
cout << "\nDlina N " << j+1 << ": ";
dist[j].showdist();
}
getch(); return 0;
}
Д/З |
Измените данную программу таким образом, чтобы она позволяла вычислять сумму элементов массива dist. |
Ответ |
class Distance { private: int feet; float inch; public: Distance() { feet=0; inch=0.0; } void getdist() { cout << "\nVvedi futy: "; cin >> feet; cout << "Vvedi duimy: "; cin >> inch; } void showdist() const { cout << feet << "'-" << inch << endl; } Distance plus(Distance a2) { Distance s; s.inch = inch + a2.inch; s.feet = 0; if(s.inch >= 12.0) { s.inch = s.inch - 12.0; s.feet++; } s.feet += feet + a2.feet; return s; } }; //------------------------------------------------------------------ int main() { const int MAX = 100; Distance dist[MAX]; int n=0, j; char ans; do { cout << "Vvod dliny N " << n+1; dist[n].getdist(); n++; cout << "\nProdol. vvod (y/n)?: "; cin >> ans; }while(ans == 'y' && n<MAX); for(j=0; j<n; j++) { cout << "\nDlina N " << j+1 << ": "; dist[j].showdist(); } cout << "\n Vychislit summu elementov(y/n): "; cin >> ans; if(ans=='y') { Distance sum; for(j=0; j<n; j++) sum = sum.plus(dist[j]); cout << "\n Summa elementov = "; sum.showdist(); } getch(); return 0; } |
Рассмотрим теперь класс Tovar на примере программы, позволяющей: 1) создавать динамический массив типа Tovar и дозаписывать его в бинарный файл; 2) считывать бинарный файл и динамически формировать массив типа Tovar.
const int N=30;
class Tovar {
private:
char name[N];
int number;
float cena;
public:
void getdata() {
cin.get();
cout << "\n Vvedite naimenovanie tovara: "; cin.getline(name, N);
cout << " Vvedite nomer tovara: "; cin >> number;
cout << " Vvedite stoimost tovara: "; cin >> cena;
}
void showdata() {
cout << name << " " << number << " " << cena;
cout << endl;
}
void savefile(char* fname) {
ofstream fout(fname, ios::binary | ios::app);
if(!fout) { cout << "\nOshibka zapisi faila!"; getch(); return; }
fout.write(name, N);
fout.write(reinterpret_cast<char*>(&number), sizeof(int));
fout.write(reinterpret_cast<char*>(&cena), sizeof(float));
fout.close();
}
void readfile(char* fname, int sme) {
ifstream fin(fname, ios::binary);
if(!fin) { cout << "\nOshibka chtenia faila!"; getch(); return ; }
fin.seekg(sme, ios::beg);
fin.read(name, N);
fin.read(reinterpret_cast<char*>(&number), sizeof(int));
fin.read(reinterpret_cast<char*>(&cena), sizeof(float));
}
};
//---------------------------------------------------------------------------
int main() {
int K, i, dfb, dlz, KZ, sm;
char otv, *filename="c:\\os\\tovar_class\\tovar3\\tovarbd.dat";
cout << "Skolko zapisei hotite dobavit: "; cin >> K;
Tovar *tm = new Tovar [K];
for(i=0; i<K; i++) {
cout << "\nZapis " << i+1 << ":" << endl;
tm[i].getdata();
}
cout << "\n Sohranit dannye?(y/n) "; cin >> otv;
if(otv=='y') {
for(i=0; i<K; i++) tm[i].savefile(filename);
cout << "\n Fail zapisan!" << endl;
}
delete [] tm;
ifstream fin(filename, ios::binary);
if(!fin) { cout << "\nOshibka chtenia faila!"; getch(); return 1; }
fin.seekg(0, ios::end); dfb = fin.tellg(); fin.seekg(0, ios::beg);
dlz = N + sizeof(int) + sizeof(float);
KZ=dfb/dlz;
fin.close();
Tovar *mas = new Tovar [KZ];
for(i=0; i<KZ; i++) {
sm=i*dlz; //смещение
mas[i].readfile(filename, sm);
}
cout << "\n Fail sodergit: " << endl;
for(i=0; i<KZ; i++) {
mas[i].showdata();
}
getch(); return 0;
}
На самом деле это не самый лучший способ решения данной задачи. Хотя это никем не оговаривается, но я считаю, что методы класса необходимо использовать не для обработки и модификации данных, а для доступа к данным класса. Рассмотрим альтернативный и более лаконичный вариант решения данной задачи, который в полной мере раскрывает отличие методов от функций.
const int N=30;
//---------------------------------------------------------------------------
class Tovar {
private:
char name[N];
int number;
float cena;
public:
void dobav_zap() {
cout << "\n Vvedite naimenovanie tovara: "; cin >> name;
cout << " Vvedite nomer tovara: "; cin >> number;
cout << " Vvedite stoimost tovara: "; cin >> cena;
}
void show() {
cout << name << " " << number << " " << cena << endl;
}
char pop(int i) {
return name[i];
}
char* getname() {
return name;
}
};
void sort(Tovar mas[], int R);
void redakt(Tovar ma[], int K);
void savefile(char* fname, Tovar *mm, int& K);
//---------------------------------------------------------------------------
int main() {
char ans;
char *fn = "c:\\os\\tovar_class\\tovar_cl.dat";
int KZ=0, dfb=0;
Tovar *m;
cout << "\n Dobavit zapis v fail?(y/n) "; cin >> ans;
if(ans=='y') {
Tovar a1;
a1.dobav_zap();
ofstream fout(fn, ios::binary | ios::app);
if(!fout) { cout << "\nOshibka faila!"; getch(); return 1; }
fout.write(reinterpret_cast<char*>(&a1), sizeof(Tovar));
fout.close();
}
cout << "\n Otsortirovat i pokazat zapisi?(y/n) "; cin >> ans;
if(ans=='y') {
ifstream fin(fn, ios::binary);
if(!fin) { cout << "\nOshibka faila!"; getch(); return 1; }
fin.seekg(0, ios::end); dfb=fin.tellg(); fin.seekg(0, ios::beg);
KZ = dfb/sizeof(Tovar);
m = new Tovar [KZ];
fin.read(reinterpret_cast<char*>(m), dfb);
fin.close();
sort(m, KZ);
for(int i=0; i<KZ; i++) m[i].show();
cout << "\n Budete redaktirovat zapisi?(y/n) "; cin >> ans;
if(ans=='y') {
redakt(m, KZ);
cout << "\n Sohranit dannye?(y/n) "; cin >> ans;
if(ans=='y') savefile(fn, m, KZ);
}
}
getch(); return 0;
}
//---------------------------------------------------------------------------
void sort(Tovar mas[], int R) {
int i, j;
for(i=0; i<R-1; i++) {
for(j=i+1; j<R; j++) {
if(mas[j].pop(0) < mas[i].pop(0)) {
Tovar a = mas[i]; mas[i] = mas[j]; mas[j] = a;
}
}
}
}
//---------------------------------------------------------------------------
void redakt(Tovar ma[], int K) {
char namer[N];
cout << "\n Ukagite naimenovanie tovara: "; cin >> namer;
int l = strlen(namer);
int ks=0;
for(int i=0; i<K; i++) {
if(strncmp(namer, ma[i].getname(), l)==NULL) {
ma[i].dobav_zap();
ks++;
}
}
if(ks==0) { cout << "\n Takogo reisa net !"; }
}
//---------------------------------------------------------------------------
void savefile(char* fname, Tovar *mm, int& K) {
ofstream fout(fname, ios::binary);
if(!fout) { cout << "\nOshibka faila!"; getch(); return ; }
fout.write(reinterpret_cast<char*>(mm), sizeof(Tovar)*K);
cout << "\n Dannye sohraneny.";
fout.close();
}