Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторные работы по ООП.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
612.86 Кб
Скачать

Оглавление

ЛР №1 - стр. №2 1

ЛР №2 – стр. №10 1

ЛР №3 – стр. №17 1

ЛР №4 – стр. № 22 1

ЛР №5 – стр. №31 1

Всё остальное – стр. № 33. 1

Лабораторная работа 1. Классы и объекты в С++ 2

Цель работы 2

Основные сведения 2

Варианты заданий 7

Контрольные вопросы 8

Лабораторная работа 2. Наследование классов в С++ 10

Цель работы 10

Основные сведения 10

Варианты заданий 13

Контрольные вопросы 15

Лабораторная работа 3. Виртуальные функции в С++ 17

Цель работы. 17

Основные сведения 17

Варианты заданий 20

Контрольные вопросы 21

Лабораторная работа 4. Создание информационно-справочных систем на С++ 22

Цель работы. 22

Основные сведения 22

Варианты заданий 27

Контрольные вопросы 29

Лабораторная работа 5. Классы и объекты в С# 31

Цель работы 31

Основные сведения 31

Контрольные вопросы 32

Требования к отчетам 33

Литература 35

Приложения 35

1.Создание консольного приложения 35

2. Перекодировка текста в С++. 39

Всего предусмотрено выполнение 5 лабораторных работ. Первые 3 работы сдаются в 1-м модуле. При несвоевременной сдаче лабораторных работ оценка снижается.

Требования к отчету см. ниже.

Первые 4 работы должны быть выполнены на С++ как консольные приложения Visual Studio/ Builder C++/Qt . Последняя на С# в Visual Studio .

Ответы на вопросы, связанные с конкретными заданиями можно получить в [4,5].

ЛР №1 - стр. №2

ЛР №2 – стр. №10

ЛР №3 – стр. №17

ЛР №4 – стр. № 22

ЛР №5 – стр. №31

Всё остальное – стр. № 33.

Лабораторная работа 1. Классы и объекты в С++

Цель работы

Ознакомление с технологией построения классов, разработкой методов, дружественных функций и перегрузкой операций.

Основные сведения

Базовыми понятиями объектно-ориентированной программы явля­ются «объект класса» и «класс». Эти понятия аналогичны понятиям переменной и её типа. Класс еще называют абстрактным типом данных (АТД). Компонентами класса явля­ются переменные базовых типов языка и других классов, объявленных в программе, и функции, работающие с этими переменными. Обычно переменные, определенные в классе, называют полями или данными, а функции – методами класса. В С++ имеется возможность управлять доступом к полям и методам класса, в частности, введение такого порядка, при котором доступ к полям класса имеют только его методы. Объединение данных и методов работы с ними в одну языковую конструкцию с возможностью управления доступом к данным называется инкапсуляцией.

Тип класса может быть задан одним из 3-х атрибутов: class, struct, union. Имя класса становится идентификатоpом нового типа данных. Полное имя компоненты класса записывается следующим образом:

[тип_компоненты] имя_класса:: имя_компоненты, где символ :: называется оператором принадлежности. Если перед этим оператором нет имени класса, то имя определяется как глобальное, известное за пределами классов.

Для создания объекта используется так называемый конструктор класса. Конструктор похож на обычную функцию с именем, совпадающим с именем класса; конструктор не имеет типа возвращаемого значения.

Объект класса может быть создан в памяти, управляемой компилятором, и в динамической памяти с помощью функции new. В первом случае конструктор инициализирует поля объекта, во втором еще и создаёт объект. В классе может быть записано несколько конструкторов; отличаться друг от друга они должны списком параметров. Конструктор класса X может иметь любой параметр любого типа, кроме X; допускается параметр типа X& (ссылку на объект типа X). Конструктор класса X заданный в виде X(X&) называется конструктором копирования; он подразумевает создание нового объекта в свободной памяти и копирование в него ранее созданного объекта.

Если в классе не задан конструктор, то компилятор автоматически использует для создания объекта конструктор по умолчанию, который имеет пустой список параметров и пустое тело. Если в классе записан какой-либо конструктор, отличающийся от конструктора по умолчанию, а в программе требуется использовать как раз последний (например, для создания массива объектов), то программист должен определить его в классе.

Деструктор автоматически разрушает объект при выходе последнего из области видимости; деструктору предшествует символ ~. Деструктор не имеет аргументов и не возвращает значе­ния. В классе может быть только один деструктор. Если деструктор не задан в программе, то он генерируется компилятором. Если при создании объекта в конструкторе используется опера­тор new, то в деструкторе должен быть использован оператор delete.

Объявление объекта класса должно соответствовать имеющемуся конструктору. Спо­собы создания объектов те же, что и в языке С: объект может объявляться как простая перемен­ная, массив, указатель. Для создания массива объектов необходимо иметь в классе конструктор без параметров или конструктор, у которого все параметры заданы по умолчанию.

Локальные нестатические поля класса не могут инициализироваться при их объявлении в классе. Инициализация таких полей возможна только при создании объекта с помощью соот­ветствующего конструктора.

Доступ к компоненту определяется наличием (или отсутствием) в определении класса атри­бутов доступа public, private, protected. Атрибут public определяет все следующие за ним компоненты как открытые, к которым разрешен прямой доступ из любой точки про­граммы; private запрещает прямой доступ к соответствующим компонентам извне (закрытые компоненты). В классе типа class все компоненты по умолчанию private, в классах типа structpublic. Каждый атрибут, записанный в классе, отменяет действие предыду­щего. (Атрибут protected –защищенный – используется в иерархии классов).

Принятый способ использования атрибутов: данные объявляются типа private (protected в базовых классах), методы и конструктор – типа public.

Обращение к объектам-компонентам класса из текста программы вне класса может быть двояким: имя_объекта.имя_компоненты или имя_объекта->имя_компоненты. Во втором случае объект должен быть создан в свободной памяти посредством указателя. При этом предполагается, что поля класса имеют атрибут public. Если поле класса закрыто, то обращение к нему производится через открытый метод класса.

Кроме методов доступ к закрытым компонентам класса имеют так называемые дружествен­ные функции. Они не являются компонентами класса и объявляются в следующем виде:

friend тип имя (параметры);

Дружественные функции рекомендуется использовать в следующих случаях:

– при необходимости упростить форму обращения к компонентам класса: не будучи компо­нентом класса, дружественная функция при вызове не требует имени объекта;

– при необходимости использовать методы одного класса для обработки закрытых данных другого класса.

Перегрузка операций

К перегрузке стандартных операций прибегают в тех случаях, когда хотят расширить действие операции на типы операндов, отличающихся от определенных в стандарте языка, или вообще изменить смысл знака операции. Напpимеp, стандаpтная опеpация сложения может быть пеpегpужена для стpоковых данных, комплексных чисел и т.п. Естественно, что пеpегpужен-ность сохpаняет смысл только для данных того класса, в котором она пpоизведена. Перегрузка операций производится с помощью специальной функции operator согласно следующей форме:

тип operator знак_опеpации (типы аpгументов){... }.

При этом оператор-функция может быть компонентом класса или дружественной функцией.

Перегружаться могут практически все, за небольшим исключением, операции. При этом функция operator не изменяет приоритет операции и число операндов, определенных в стандартной операции.

Примеры перегрузки операций приведены ниже в определении класса Complex.

Агрегация

Два класса могут быть связаны отношением агрегации (включения). Отношение агрегации (целое/часть) между классами имеет место, когда один класс (целое) содержит в качестве компоненты объект другого класса (часть). Например, один пользовательский класс содержит компоненту, тип которой определяется другим пользовательским классом. Различают строгую и нестрогую агрегацию. В первом случае часть включается в целое как значение, во втором – в виде указателя. (Строгая агрегация еще называется композицией). На диаграммах агрегация изображается сплошной линией от класса, объект которого является частью, до класса, в который включается этот объект; линия заканчивается пустым ромбом в случае нестрогой агрегации и зачерненным в противном случае).

Например,

class Point{

public:

double x, y;

/*…..*/

};

class Triangle {

public:

Point x1, x2, x3;

/*…..*/

};

Здесь следует отметить, пожалуй, вот что. При обращении к полю или методу включенного класса из объекта включающего, вид обращения может быть таким:

void main()

{ Triangle t1;

t1.x1.x=5;

t1.x2.y=7;

……}

С точки зрения инкапсуляции данных такое обращение, хотя и работающее, но неправильное – поля класса Triangle открыты. Да и обращение с двумя точками выглядит не очень красиво. Закроем поля в Triangle.

class Triangle {

Point x1, x2, x3;

public:

void SetTriangle(double _x1, double _y1,double _x2,double _y2,double _x3,double _y3)

{x1.x=_x1;x1.y=_y1;x2.x=_x2;x2.y=_y2;x3.x=_x3;x3.y=_y3;}

};

void main(int argc, _TCHAR* argv[])

{

Triangle t1;

t1.SetTriangle(1,2,3,4,5,6);

}

Отношение включения рекомендуется использовать в некоторых вариантах лаб. работ, там, где оно выглядит естественным. Например, игральная карта и колода карт. Между тем, заметьте, что записывая Triangle t1 в main мы тоже, по большому счету, занимаемся включением. Так, конечно, не говорят – main не класс, а функция. ( В C#, кстати, main является членом класса.) Предположим, что мы решили обойтись одним классом Карта. Очевидно, что колода является массивом карт и что мы должны тогда в main организовывать массив и его обработку. В ООП та конструкция, которая управляет программой, называется клиентом. В клиенте не должны быть видны подробности организации программы, в частности, поля классов и действия клиента должны быть максимально простыми. Используя дополнительный класс и включение мы можем решить эти задачи.

В первой работе, которая предназначена для изучения основ, я не настаиваю на упрощении main, но, начиная со 2-й, это требование должно соблюдаться.

Пример выполнения работы

Ниже приводится определeние класса комплексных чисел Complex, в котором ввод чисел производится в алгебраической форме, операции умножения и деления производятся в полярной системе координат.

Графическое изображение класса включает имя класса, его поля и методы. (В скобках даны русские названия, которые необязательно являются буквальным переводом.) На диаграмме закрытому компоненту предшествует символ -, открытому – символ +.

Complex

- real : double (ДействительнаяЧасть)

- image: double (МнимаяЧасть)

+Complex (void):Конструктор

+~Complex (void):Деструктор

+InputComplex: void (ВводЧисла )

+ShowComlex: void (ВыводЧисла )

+Operator +:Complex (Сложение чисел)

+Operator *: Complex (УмножениеЧисел )

+Operator / : Complex (ДелениеЧисел )

Ниже приведена программа реализация класса Complex в проекте на Visual Studio. Проект включает 3 файла: заголовочный - Complex.h , реализации - Complex.cpp и функции main - MyComplex.cpp.

//complex.h

#pragma once

class Complex

{

double real;

double image;

public:

Complex();

void InputComplex();

void ShowComplex () const;

//Перегрузка операций сложения, умножения и деления комплексных чисел

Complex operator + (Complex);

Complex operator * (Complex );

Complex operator / (Complex);

~Complex(void);

};

//сommplex.cpp

#include "Complex.h"

#include <iostream>

#include <math.h>

using namespace std;

Complex::Complex(void){ }

Complex::~Complex(void) { }

//Ввод дествительной и мнимой части

void Complex::InputComplex() {

double re,im;

cout<<"Input real part "; cin>>re;

cout<<"Input image part "; cin>>im;

real=re;

image=im;

}

//Вывод числа на консоль

void Complex::ShowComplex()const{

cout<<real<<" +i"<<image<<endl;

}

/*Перегруженные операции +, * и /.

При выполнении операций умножения и деления производится преобразование комплексного числа из введенной прямоугольной системы в полярные координаты, в которых и выполняется соответствующая операция. После операции производится обратное преобразование координат*/

Complex Complex:: operator + (Complex t)

{ Complex tmp;

tmp.real=real+t.real;

tmp.image=image+t.image;

return tmp;

}

Complex Complex::operator *(Complex t){

Complex tmp;

double arg, mod, arg1, mod1;

// Вычисление модулей аргументов операции

mod=sqrt(pow(real,2)+pow(image,2));

mod1=sqrt(pow(t.real, 2)+pow (t.image,2));

//Вычисление и проверка углов

if (real==0) { cout<< "denominator = 0";int g; cin<<g; exit(1);}

if(real>0)

{

if(image>0)

arg=(atan(image/real));

else arg=6.28+atan(image/real);

}

else arg=3.14+atan(image/real);

if(t.real>0)

{

if(t.image>0)

arg1=atan(t.image/t.real);

else arg1=6.28+atan(t.image/t.real);

}

else arg1=3.14+atan(t.image/t.real);

tmp.real=mod*mod1*(cos(arg+arg1));

tmp.image=mod*mod1*(sin(arg+arg1));

return tmp;

}

//Перегрузка операции деления

Complex Complex::operator / (Complex t)

{

Complex tmp;

double arg,mod,arg1,mod1;

mod=sqrt(pow(real,2)+pow(image,2));

mod1=sqrt(pow(t.real, 2)+pow (t.image,2));

if(real==0) throw 1;

if(real>0)

//Преобразование координат

if(image>0) arg=atan(image/real);

else arg=6.28+atan(image/real);

else arg=3.14+atan(image/real);

if(t.real>0)

{

if(t.image>0) arg1=atan(t.image/t.real);

else arg1=6.28+atan(t.image/t.real);

}

else arg1=3.14+atan(t.image/t.real);

if (mod1==0) throw 1;

tmp.real=(mod*mod1*cos(arg-arg1))/(mod1*mod1);

tmp.image=(mod*mod1*sin(arg-arg1))/(mod1*mod1);

return tmp;

}

//MyComplex.cpp

#include "stdafx.h"

#include "Complex.h"

int _tmain(int argc, _TCHAR* argv[])

{

Complex cm1, cm2, cm3;

cm1.InputComplex();

cm2.InputComplex();

cm3=cm1+cm2;

cm3.ShowComplex();

cm3=cm1*cm2;

cm3.ShowComplex();

return 0;

}