Uploaded by Asya Moroz

Объективно-ориентированное программирование, виртуальные функции

advertisement
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ
ВЫСШЕГО ОБРАЗОВАНИЯ
МОСКОВСКИЙ ПОЛИТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
ВЫСШАЯ ШКОЛА ПЕЧАТИ И МЕДИАИНДУСТРИИ
Институт Принтмедиа и информационных технологий
Кафедра Информатики и информационных технологий
направление подготовки
09.03.02 «Информационные системы и технологии»
ЛАБОРАТОРНАЯ РАБОТА № _9_
Дисциплина:
Тема:
Объектно-ориентированное программирование
Виртуальные функции
Выполнил: студент группы
211-729
Мороз Анастасия Сергеевна
(Фамилия И.О.)
Дата, подпись
02.06.2022
(Дата)
(Подпись)
Проверил:
(Фамилия И.О., степень, звание)
(Оценка)
Дата, подпись
(Дата)
Замечания:
Москва
2022
(Подпись)
Лабораторная работа №9
Цель: получить практические навыки в создании программ,
использующих структуры и перечисления.
Постановка задачи:
1. Разработать программы, реализующие задания, приводимые
ниже.
2. Оформить отчет, содержащий следующие пункты:
1. Титульный лист.
2. Название и цель работы.
3. Постановка задачи.
4. Листинг программы с комментариями.
Листинг программы:
5)
Предположим, что в функции main() определены три локальных массива одинакового размера и типа
(скажем, float). Первые два уже инициализированы значениями. Напишите функцию addarrays(),
которая принимает в качестве аргументов адреса грех массивов, складывает соответствующие
элементы двух массивов и помещает результат в третий массив. Четвертым аргументом этой функции
может быть размерность массивов. На всем протяжении программы используйте указатели.
#include <iostream>
using namespace std;
const int N = 5;
void Function(int p1[], int p2[], int p3[]);
int main()
{
setlocale(LC_ALL, "");
int p1[N]{ 1,2,3,4,5 }, p2[N]{ 2,3,4,5 ,6}, p3[N];
Function(p1, p2, p3);
}
void Function(int p1[], int p2[], int p3[]) {
for (int i = 0; i < N; i++)
{
p3[i] = p1[i] + p2[i];
}
for (int i = 0; i < N; i++)
{
cout << "№ : " << i << " Элемент : " << p3[i] << endl;
}
}
6)
Создайте свою версию библиотечной функции strcmp(s1, s2), которая сравнивает две строки и
возвращает -1, если s1 идет первой по алфавиту, О, если в s1 и s2 одинаковые значения, и 1, если s2
идет первой по алфавиту. Назовите вашу функцию compstr(). Она должна принимать в качестве
аргументов два указателя на строки char *, сравнивать эти строки посимвольно и возвращать число int.
Напишите функцию main() для проверки работы вашей функции с разными строками. Используйте
указатели во всех возможных ситуациях.
#include <iostream>
using namespace std;
const int N = 3;
void Function(char p1[], char p2[]); //объявление функции
int main()
{
setlocale(LC_ALL, "");
char p1[N] = "GH", p2[N] = "MH"; // ввод строчек для сравнения
Function(p1, p2); // применение функции
}
void Function(char p1[], char p2[]) {
int m = 0;
for (int i = 0; i < N - 1; i++) // запуск цикла для прогонки функции по каждой
букве
{
if ((int)p1[i] > (int)p2[i]) {
m++;
cout << "-1 ";
exit(0); // если первая сторока по алфовиту первыя, вывод 1, цикл
прерывается
}
if ((int)p1[i] < (int)p2[i]) {
m++;
cout << "1 ";
exit(0); // если вторая сторока по алфовиту первыя, вывод -1, цикл
прерывается
}
}
if (m == 0) {
cout << "0 "; // если строки иденичны
}
}
7)
Модифицируйте класс person из программы, представленной ниже, чтобы он включал в себя не только
имя человека, но и сведения о его зарплате в виде поля salary типа float.
Вам будет необходимо изменить методы setName() и printName() на setData() и printData(), включив в
них возможность ввода и вывода значения salary, как это можно сделать с именем. Вам также
понадобится метод getSalary(). Используя указатели, напишите функцию salsortQ, которая сортирует
указатели массива persPtr по значениям зарплаты. Попробуйте вместить всю сортировку в функцию
salsort(), не вызывая других функций, как это сделано в программе PERS0RT. При этом не забывайте,
что операция -> имеет больший приоритет, чем операция *, и вам нужно будет написать
#include <iostream>
#include <iomanip>
#include <conio.h>
#include <sstream>
#include <string.h>
using namespace std;
class person // создание класса
{
protected:
string name;
float salary;
public:
void setData() // метод заполнения
{
cout << "Введите имя: ";
cin >> name;
cout << "ВВедите зарплату : "; cin >> salary;
}
void printData() // метод для вывода данных класса
{
cout << endl << "Имя: " << name << ", Зарплата: " << salary;
}
string getName() // метод воззвращающий имя
{
return name;
}
float getSalary()// метод воззвращающий зарплату
{
return salary;
}
};
void bsort(person** pp, int n) // метод для сортировки
{
void order(person**, person**);
int j, k;
for (j = 0; j < n - 1; j++)
for (k = j + 1; k < n; k++)
order(pp + j, pp + k);
}
void salsort(person** pp, int n) {
int j, k;
for (j = 0; j < n - 1; j++)
for (k = 1; k < n; k++)
if ((*(pp + j))->getSalary() > (*(pp + k))->getSalary())
{
swap(*(pp + j), *(pp + k));
}
}
void order(person** pp1, person** pp2) // метод меняющий классы местами
{
if ((*pp1)->getName() > (*pp2)->getName())
{
swap(*pp1, *pp2);
}
}
/////////////////////////////////////////////////////////////////////////7
int main() {
setlocale(LC_ALL, "");
void bsort(person**, int);
void salsort(person**, int);
person* persPtr[100];
int n = 0;
char choice;
do
{
persPtr[n] = new person;
persPtr[n]->setData();
n++;
cout << "Продолжать ввод (y/n)?";
cin >> choice;
} while (choice == 'y');
cout << "\nНеотсортированный список :";
for (int j = 0; j < n; j++)
persPtr[j]->printData();
salsort(persPtr, n);
cout << "\nОтсортированный список :";
for (int j = 0; j < n; j++)
persPtr[j]->printData();
cout << endl;
}
8)
Исправьте функцию additem() из программы связного списка так, чтобы она добавляла новый элемент
в конец списка, а не в начало. Это будет означать, что первый вставленный элемент будет выведен
первым и результат работы программы будет следующим:
#include <iostream>
using namespace std;
int n = 0;
////////////////////////////////////////////////////////////////
struct link
//один элемент списка
{
int data;
//элемент данных
link* next;
//указатель на следующую ссылку
};
////////////////////////////////////////////////////////////////
class linklist
//список ссылок
{
private:
link* first;
//указатель на первую ссылку
public:
linklist()
//конструктор по умолчанию
{
first = NULL;
}
//нет первой ссылки
void additem(int d);
//добавить элемент данных (одна ссылка)
void display();
//добавить элемент данных (одна ссылка)
};
//-------------------------------------------------------------void linklist::additem(int d)
{
link* newlink = new link;
newlink->data = d;
if (first)
{
link* p = first;
while (p->next)
p = p->next;
p->next = newlink;
}
else
first = newlink;
newlink->next = NULL;
}
//-------------------------------------------------------------void linklist::display()
//показать все ссылки
{
link* current = first;
//установить ptr на первую ссылку
while (current != NULL)
//выйти по последней ссылке
{
cout << current->data << endl; //распечатать данные
current = current->next;
//перейти к следующей ссылке
}
delete current;
}
////////////////////////////////////////////////////////////////
int main()
{
linklist l;
//сделать связанный список
l.additem(25);
l.additem(36);
l.additem(49);
l.additem(64);
//добавить четыре элемента в список
l.display();
return 0;
//показать весь список
}
9)
Допустим, что нам нужно сохранить 100 целых чисел так, чтобы иметь к ним легкий доступ. Допустим,
что при этом у нас есть проблема: память нашего компьютера так фрагментирована, что может
хранить массив, наибольшее количество элементов в котором равно десяти (такие проблемы
действительно появляются, хотя обычно это происходит с объектами, занимающими большое
количество памяти). Вы можете решить эту проблему, определив 10 разных массивов по 10 элементов
в каждом и массив из 10 указателей на эти массивы. Массивы будут иметь имена а0, a1, а2 и т. д.
Адрес каждого массива будет сохранен в массиве указателей типа int*, который называется ар. Вы
сможете получить доступ к отдельному целому используя выражение ap[j] [к], где j является номером
элемента массива указателей, а к — номером элемента в массиве, на который этот указатель
указывает. Это похоже на двумерный массив, но в действительности является группой одномерных
массивов.
Заполните группу массивов тестовыми данными (скажем, номерами 0, 10, 20 и т. д
#include <iostream>
#include <string>
#include <iomanip>
#include <cmath>
using namespace std;
const int N = 10;
int main()
{
int A = 0;
setlocale(LC_ALL, "");
int a[N], b[N], c[N], d[N], e[N], f[N], g[N], h[N], r[N], t[N]; // создание 10 массивов размера N
int* p[] = { a,b,c,d,e,f,g,h,r,t }; // создание массива указателей
for (int i = 0; i < 10; i++) {// функция заполнения массива указателей на массивы
for (int q = 0; q < 10; q++) {
p[i][q] = A++;
}
}
for (int i = 0; i < 10; i++) {// функция вывода массива указателей на массивы
cout << "Массив " << i << ": ";
for (int q = 0; q < 10; q++) {
cout << p[i][q] << " ";
}
cout << endl;
}
}
10) Описанный в упражнении 9 подход нерационален, так как каждый из 10 массивов объявляется
отдельно, с использованием отдельного имени, и каждый адрес получают отдельно. Вы можете
упростить программу, используя операцию new, которая позволит вам выделить память для массивов
в цикле и одновременно связать с ними указатели:
for ( j = 0: j < NUMARRAYS; j++ )
// создаем NUMARRAYS массивов
*( ар + j ) = new int [ MAXSIZE ]: //no MAXSIZE целых чисел в каждом
Перепишите программу упражнения 9, используя этот подход. Доступ к отдельному элементу массивов
вы сможете получить, используя то же выражение, что и в упражнении 9, или аналогичное выражение
с указателями: *(*(ap+j)+k).
#include <iostream>
#include <string>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
int A = 0;
setlocale(LC_ALL, "");
int n = 10, m = 10;
int** a = new int* [n];
// создание указателя на указатель (массив указателей)
int* ap; // объявление указателя
ap = *a; // присвоение указателя
for (int j = 0; j < n; j++) { // цикл заполнения
ap = new int[m] - j;
a[j] = (ap + j);
for (int i = 0; i < m; i++) {
a[j][i] = A++;
}
}
for (int i = 0; i < n; i++) {// цикл вывода
cout << "Массив " << i << ": ";
for (int q = 0; q < m; q++) {
cout << a[i][q] << " ";
}
cout << endl;
}
delete a;
}
11)
Создайте класс, который позволит вам использовать 10 отдельных массивов из упражнения 10 как
один одномерный массив, допуская применение операций массива. То есть мы можем получить доступ
к элементам массива, записав в функции main() выражение типа a[j], а методы класса могут получить
доступ к полям класса, используя двухшаговый подход. Перегрузим операцию [ ], чтобы получить
нужный нам результат. Заполним массив данными и выведем их. Хотя для интерфейса класса
использованы операции индексации массива, вам следует использовать указатели внутри методов
класса.
#include<iostream>
using namespace std;
class tenmas // создания класса для работы с массиврм
{
private:
int** mas;
public:
tenmas() // создание конструктора по умолчанию
{
mas = new int* [10]; // освоюождение памяти для 10 элементов памяти
for (int i = 0; i < 10; i++)
{
*(mas + i) = new int[10];
}
}
void input(int x, int y, int n)
{
*(*(mas + x) + y) = n;
}
void input(int* x, int y, int n) // перегрузка функции input
{
*(x + y) = n;
}
void print(int x, int y, int n)
{
cout << *(*(mas + x) + y) << endl;
}
void print(int* x, int y) // перегрузка функции print
{
cout << *(x + y) << endl;
}
int* operator [](int a)
{
return *(mas + a);
}
};
int main()
{
setlocale(LC_ALL, "Russian");
tenmas tm;
tm.input(tm[2], 3, 4);
tm.print(tm[2], 3);
return 0;
}
12)
Указатели сложны, поэтому давайте посмотрим, сможем ли мы сделать работу с ними более понятной
(или, возможно, более непонятной), используя их симуляцию в классе.
Для разъяснения действия наших доморощенных указателей мы смоделируем память компьютера с
помощью массивов. Так как доступ к массивам всем понятен, то вы сможете увидеть, что реально
происходит, когда мы используем для доступа к памяти указатели.
Мы будем использовать один массив типа char для хранения всех типов переменных. Именно так
устроена память компьютера: массив байтов (тип char имеет тот же размер), каждый из которых имеет
адрес (или, в терминах массива, индекс). Однако
C++ не позволит нам хранить данные типа float или int в массиве типа char обычным путем (мы можем
использовать объединения, но это другая история). Поэтому мы создадим симулятор памяти,
используя отдельный массив для каждого типа данных, которые мы хотим сохранить. В этом
упражнении мы ограничимся одним типом float, и нам понадобится массив для него. Назовем этот
массив fmemory. Однако значения указателей (адреса) тоже хранятся в памяти, и нам понадобится
еще один массив для их хранения. Так как в качестве модели адресов мы используем индексы
массива, то нам потребуется массив типа int, назовем его pmemory, для хранения этих индексов.
#include <iostream>
#include <iomanip>
#include <conio.h>
#include <sstream>
#include <string.h>
using namespace std;
float fmemory[100];
int fmem_top = 0;
int pmemory[100];
int pmem_top = 0;
class Float
{
int addr = -1;
public:
Float(float f)
{
fmemory[fmem_top] = f;
addr = fmem_top++;
}
int operator & ()
{
return addr;
}
};
class ptrFloat
{
int addr;
public: ptrFloat(int i)
{
pmemory[pmem_top] = i;
addr = pmem_top++;
}
float& operator * ()
{
return fmemory[pmemory[addr]];
}
};
int main() {
Float f1 = 1.234;
Float f2 = 5.678;
ptrFloat p1 = &f1;
ptrFloat p2 = &f2;
cout << "*p1 = " << *p1 << endl << "*p2 = " << *p2 << endl;
*p1 = 7.123;
*p2 = 8.456;
cout << "*p1 = " << *p1 << endl << "*p2 = " << *p2 << endl;
}
Download
Study collections