Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

hkjCJgcQqF

.pdf
Скачиваний:
2
Добавлен:
15.04.2023
Размер:
810.94 Кб
Скачать

ivar2 = m;

}

int sum (MyClass obj)

{

return obj.ivar1+ obj.ivar2;

}

int main ( ) { MyClass ob; ob.set_var (5, 7); cout << sum(ob); return 0; }

В данном примере функция sum () не является членом класса, но она обладает полным доступом к закрытым членам. Поскольку функция sum () не является членом класса, ей не нужно указывать имя объекта, и ее можно вызывать без помощи оператора “.” .

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

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

Дружественные классы

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

Пример программы применения дружественного класса. #include <iostream>

using namespace std; class MyClass

{

private:

int ivar1; int ivar2;

public:

MyClass (int k, int m ) { ivar1 = k; ivar2 = m; } friend class Max;

};

class Max

{

23

public:

int max(MyClass obj);

};

int Max::max(MyClass obj)

{

return obj.ivar1 > obj.ivar2 ? obj.ivar1 : obj.ivar2;

}

int main ( )

{

MyClass ob (57, 41); Max m;

cout << m.max(ob) <<endl ; return 0;

}

В данном примере класс Max имеет доступ к закрытым переменным ivar1 и ivar2 , объявленным в классе MyClass.

Если один класс является дружественным по отношению к другому, он просто получает доступ к сущностям, определенным в этом классе, но не наследует их, т.е. члены класса не становятся членами дружественного класса.

Лабораторная работа № 1-а Тема: Создание классов

Цель: Разработать и использовать класс на примере верхней треугольной матрицы.

Краткие теоретические сведения

В верхней треугольной матрице все элементы, находящиеся ниже главной диагонали, имеют нулевые значения (Ai,j =0 для j<i). Верхний треугольник определяется элементами Ai,j для j ≥ i.

Свойства верхней треугольной матрицы

Если верхняя треугольная матрица имеет n2 элементов, приблизительно половина из них являются нулевыми и не надо сохранять их явно.

Хранение треугольной матрицы:

Строка

Число элементов

Элементы

0

n

(A0,0

... A0,n-1 )

1

n-1

(A1,1

... A1,n-1 )

2

n-2

(A2,2

... A2,n-1 )

...

...

...

 

 

n-2

2

(An-2,n-2

... An-2,n-1 )

n-1

1

(An-1,n-1

)

24

Алгоритму сохранения требуется функция доступа, которая должна определять местоположение в массиве M элемента Ai,j . Для j ≥ i функция доступа использует информацию о числе сохраняемых элементов в каждой строке в массиве (rowTable). С учетом того, что элементы треугольной матрицы сохраняются построчно в массиве M , функция доступа для Ai,j использует следующие параметры:

Индексы i и j, Массив rowTable.

Алгоритм доступа к элементу Ai,j заключается в следующем: Если j<i , Ai,j =0 и этот элемент не сохраняется.

Если j i, то получается значение rowTable[i], являющееся количеством элементов, которые сохраняются в массиве M , для элементов до строки i. В строке i первые i элементов являются нулевыми и не сохраняются в М. Элемент Ai,j помещается в M[rowTable[i]+(j-i)].

Для работы с верхней треугольной матрицей разработан класс

TriMat.

Спецификация класса TriMat. //Заголовочный файл trimat.h #ifndef TRIMAT_CLASS #define TRIMAT_CLASS

//#ifndef -директива условной компиляции -if not defined -если не определено

//#define -директива #include <iostream.h> #include <iomanip.h> #include <stdlib.h> using namespace std;

//Объявление класса

//максимальное число элементов и строк верхней треугольной матрицы

const int ELEMENTLIMIT = 325; const int ROWLIMIT = 25;

class TriMat

{

private:

 

// закрытые данные-члены

 

int rowTable[ROWLIMIT];

// начальный индекс строки в M

int n;

// размер строки/колонки

double M[ELEMENTLIMIT];

// запись верхних элементов

public:

 

// конструктор с параметрами TriMat(int matsize);

// методы доступа к элементам матрицы

25

void PutElement (double item, int i, int j); double GetElement(int i, int j) const;

// матричные арифметические операции TriMat AddMat(const TriMat& A) const; double DetMat( ) const;

// матричные операции ввода/вывода void ReadMat( );

void WriteMat( ) const;

// получить размерность матрицы int GetDimension( ) const;

}; Конструктор принимает число строк и столбцов матрицы. Методы

PutElement и GetElement сохраняют и возвращают элементы верхней треугольной матрицы. GetElement возвращает 0 для элементов ниже диагонали. Метод AddMat возвращает сумму матрицы А с текущим объектом. Этот метод не изменяет значение текущей матрицы. Операторы ввода/вывода ReadMat и WriteMat работают со всеми элементами матрицы n x n. Сам метод ReadMat сохраняет только верхне-треугольные элементы матрицы.

Описание

Конструктор инициализирует закрытый член n параметром matsize. Таким образом задается число строк и столбцов матрицы. Этот же параметр используется для инициализации массива rowTable, который используется для доступа к элементам матрицы. Если matsize превышает ROWLIMIT, выдается сообщение об ошибке и выполнение программы прерывается.

TriMat::TriMat(int matsize)

{

int storedElements = 0;// число записанных элементов в начале =0 // прервать программу, если matsize больше ROWLIMIT

if (matsize > ROWLIMIT)

{

cerr << "Превышен размер матрицы " << ROWLIMIT << "x " << ROWLIMIT << endl;

exit(1);

}

n = matsize;

// задать таблицу for(int i = 0; i < n; i++)

{

rowTable[i] = storedElements; storedElements += n - i;

26

}

}

// возвратить размерность матрицы n int TriMat::GetDimension( ) const

{

return n;

}

Метод GetDimension предоставляет клиенту доступ к размеру таблицы. Эта информация может использоваться для обеспечения того, чтобы методам доступа передавались параметры, соответствующие правильной строке и столбцу.

Записать элемент матрицы [i,j] в массив M: void TriMat::PutElement (double item, int i, int j)

{

//прервать программу, если индексы элемента вне индексного диапазона

if ((i < 0 || i >= n) || (j < 0 || j >= n))

{

cerr << "PutElement: индекс вне диапазона 0 - " << (n-1) << endl;

exit (1);

}

// все элементы ниже диагонали игнорируются if (j >= i)

M[rowTable[i] + j-i] = item;

}

Для получения любого элемента метод GetElement проверяет индексы i и j. Если i или j не находятся в диапазоне от 0 до (n-1), программа заканчивается. Если j< i , то элемент находится в нижней треугольной матрице со значением 0, то метод GetElement просто возвращает несохраненное значение 0. В противном случае, j ≥ i , и метод доступа будет возвращать элемент из массива М.

Реализация метода GetElement (получение элемента матрицы [i,j] из массива M):

double TriMat::GetElement(int i,int j) const

{

// прервать программу . если индексы вне индексного диапазона if ((i < 0 || i >= n) || (j < 0 || j >= n))

{

cerr << "PutElement: индекс вне диапазона 0 - " << (n-1) << endl;

exit (1);

}

27

if (j >= i)

// вернуть элемент, если он выше диагонали return M[rowTable[i] + j-i];

else

// элемент равен 0., если он ниже диагонали return 0;

}

Ввод-вывод матричных объектов

Традиционно ввод матрицы подразумевает, что данные вводятся построчно с полным набором значений строк, и столбцов. В объекте TriMat нижняя треугольная матрица является нулевой и значения не сохраняются в массиве, но их надо вводить!!!

// читать элементы матрицы построчно, пользователь должен ввести все (n x n ) элементов

void TriMat::ReadMat(void)

{

double item;

 

int i, j;

 

for (i = 0; i < n; i++)

// сканировать строки

for (j = 0; j < n; j++) // для каждой строки сканировать столбцы

{

 

cin >> item;

// читать [i,j]-й элемент матрицы

PutElement(item,i,j);

// сохранить этот элемент

}

 

}

Построчная выдача в поток элементов матрицы void TriMat::WriteMat( ) const

{

int i,j;

// установка режима вывода , cout.setf(ios::fixed); cout.precision(3); cout.setf(ios::showpoint);

for (i = 0; i < n; i++)

{

for (j = 0; j < n; j++)

cout << setw(7) << GetElement(i,j); cout << endl;

}

}

Матричные операции

Метод AddMat принимает единственный параметр, который является правым операндом в сумме. Текущий объект соответствует левому

28

операнду. Например, сумма треугольных матриц X и Y использует метод AddMat для объекта X. Предположим, сумма сохраняется в объекте Z. Для вычисления

Z=X+Y

используйте оператор Z=X.AddMat(Y);

Алгоритм сложения двух объектов типа TriMat возвращает новую матрицу B с элементами Bi,j=CurrentObjecti,j+Ai,j;

возвращает сумму текущей и матрицы A. Текущий объект не изменяется.

TriMat TriMat::AddMat(const TriMat& A) const

{

int i, j;

double itemCurrent, itemA;

TriMat B(A.n); // в B будет искомая сумма

for (i = 0; i < n; i++)

// цикл по строкам

{

 

for (j = i; j < n; j++) // пропускать элементы ниже диагонали

{

itemCurrent = GetElement(i,j); itemA = A.GetElement(i,j);

B.PutElement(itemCurrent + itemA, i, j);

}

}

return B;

}

//детерминант текущего объекта double TriMat::DetMat(void) const

{

double val = 1.0;

//детерминант – произведение элементов диагонали

for (int i = 0; i < n; i++) val *= GetElement(i,i); return val;

}

#endif // TRIMAT_CLASS

//Программа для работы с верхней треугольной матрицей

#include <cstdlib>

 

#include <iostream >

 

#include <iomanip>

 

#pragma hdrstop

 

using namespace std;

 

#include "trimat.h"

// включить класс TriMat

29

int main(int argc, char *argv[])

{

int n;

//Задать размер однородной матрицы cout << "Каков размер матрицы? "; cin >> n;

//объявить три матрицы размером ( n x n ) TriMat A(n), B(n), C(n);

//читать матрицы A и B

cout << "Введите некоторую " << n << " x " << n

<<" треугольную матрицу " << endl; A.ReadMat();

cout << endl;

cout << "Введите некоторую " << n << " x " << n

<<" треугольную матрицу " << endl; B.ReadMat();

cout << endl;

//выполнить операции и напечатать результат cout << "Сумма A + B" << endl;

C = A.AddMat(B); C.WriteMat(); cout << endl;

cout << "Детерминант A+B= " << C.DetMat() << endl;

system("PAUSE");

return EXIT_SUCCESS;

}

Задание № 1

1.Используя листинги заголовочного файла TriMat.h и программы, реализующей класс верхней треугольной матрицы, создайте приложение и проверьте правильность подсчета суммы и детерминанта.

2.Создайте метод подсчета произведения и вычитания двух матриц. Проверьте правильность расчета.

3.При решении общей n x n системы алгебраических уравнений ряд операций сводит задачу к решению уравнения треугольной матрицы. Разработайте функцию void SolveEqn(const TriMat& A, double X[],double C[]); Она определяет единственное решение, если оно существует, общего уравнения треугольной матрицы.

4.Создайте в приложении массив объектов TriMat, инициализируйте его, выведите значения элементов матрицы, примените операции умножения, вычитания к элементам массива объектов TriMat.

№ 2

30

1. Реализуйте для каждого из данных классов копирующий конструктор, конструктор по умолчанию и деструктор.

( a) class BinStrTreeNode { public:

// ...

private:

string _value; int _count;

BinStrTreeNode *_leftchild; BinStrTreeNode *_rightchild

};

class BinStrTree { public:

// … private:

BinStrTreeNode *_root

};

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

1. Объясните использование ключевого слова const в разных контекстах приведенной программы, реализующей класс верхней треугольной матрицы.

2.Объясните, как в классе TriMat реализован конструктор?

3.Как установить режим выдачи потока?

4.Определите все ошибки синтаксиса в определениях класса: class X

{private int t; private int q;

public

int X(int a, int b);

{

t=a; q=b;

}

void printX( );

}

classY

{

private: int p; int q;

public

Y (int n, int m) : n(p) q(m); };

5. Объявите спецификацию для класса X, который имеет следующее:

31

Закрытые члены: Целые переменные a, b, c.

Открытые члены: Конструктор, который присваивает значения переменным a,b,c; значения по умолчанию будут равны 1. Функцию F, возвращающую максимум переменных a,b,c.

6. Напишите конструктор для класса X, открытую функцию F, поместив ее определение вне класса. Напишите программу, использующую класс X.

Лабораторная работа № 1-б Тема: Объекты и классы языка С++

Цель: Научиться создавать пользовательские классы. Задание

1. В морской навигации координаты точки измеряются в градусах

иминутах. Долгота измеряется величиной от 0 до 180 градусов восточнее или западнее Гринвича. Широта принимает значения от 0 до 90 градусов севернее или южнее экватора. Создайте класс Angle, включающий следующие три поля: типа int для числа градусов, типа float для числа минут и типа char для указания направления (N, S, E или W).Объект этого класса может содержать значение, как широты, так и долготы. Создайте метод, позволяющий ввести координату точки, направление, в котором она измеряется, и метод, выводящий на экран значение этой координаты. Кроме того, напишите конструктор, который принимает три аргумента. Напишите функцию (main()), которая сначала создает переменную с помощью трехаргументного конструктора и выводит ее значение на экран, а затем циклически запрашивает у пользователя ввести значение координаты и отображает введенное значение на экране.

2. Создайте класс, одно из полей которого хранит “порядковый номер” объекта, т.е. для первого созданного объекта значение этого поля равно 1, для второго созданного объекта значение равно 2 и т.д. Для того чтобы создать такое поле, вам необходимо иметь еще одно поле, в которое будет записываться количество созданных объектов класса (это означает, что поле должно относиться не к отдельным объектам класса, а ко всему классу в целом). Каждый раз при создании нового объекта конструктор может получить значение этого поля и в соответствии с ним назначить объекту индивидуальный порядковый номер.

В класс следует включить метод, который будет выводить на экран порядковый номер объекта. Создайте функцию (main( ) ), в которой будут созданы три объекта, и каждый объект выведет на экран свой порядковый номер.

3. Создайте класс Ship, который будет содержать данные об учетном номере корабля и координатах его расположения. Для задания номера корабля следует использовать механизм, аналогичный описанному в упражнении №2. Для хранения координат используйте два поля типа Angle

32

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]