Использование proxy-классов

 

Мета роботи

 

Отримати практичні навички застосування proxy-классов на С++

 

2 Методичні вказівки до організації самостійної роботи студентів

 

Создание многомерного массива в виде Proxy – класса.

Задача. Создать динамический многомерный массив, который бы поддерживал операцию доступа по индексу [][]...[].

Так, например необходимо создать двумерный динамический массив T Array2D, который бы поддерживал доступ через операцию [][].

Поскольку функции operator [ ] [ ] в языке С++ нет, перегрузим функцию operator [ ] так, чтобы она возвращала новый класс ArraylD (одномерный динамический массив). Затем снова пере­грузить функцию operator [ ] в классе ArraylD, в результате чего она будет воз­вращать элемент в исходном двумерном массиве:

class Array2D

{

public:

class ArraylD

{

private:

int dim2;

T * Array1;

public:

friend class Array2D ;

ArraylD():Array1(NULL),dim2(0) {}

T& operator[](int index);

const T& operator[] (int index) const;

}; //class ArraylD

private:

int dim1;

ArraylD* Array2;

public:

Array2D():dim1(0),Array2(NULL){};

Array2D(int d1, int d2);

virtual ~Array2D();

ArraylD& operator[] (int index);

const ArraylD& operator[] (int index) const;

};

Тогда становится допустимым следующее:

Array2D<float> datad(10, 20);

data[3][6] = 10; // Нормально.

cout<<data[3][6] ; // Нормально.

 

В данном случае data [3] обозначает объект ArraylD.

 

Объекты, кото­рые обозначают другие объекты, называются proxy-объектами (proxy objects), а классы, на основе которых создаются proxy-объекты, часто называются proxy-классами (proxy classes).

 

В приведенном примере ArraylD является proxy-классом. Экземпляры объектов этого класса соответствуют одномерным массивам, которые теоретически не существуют. (Терминология proxy-классов и объектов не являет­ся универсальной; иногда объекты таких классов называются заместителями (surrogates).)

 

Пользователи класса Array2D не обязательно должны знать о существовании класса ArraylD. Объекты последнего класса представляют собой одномерные массивы, которые не существуют с точки зрения клиентов класса Array2D. Пользовательские приложения пишутся так, как будто они используют реальные двумерные массивы. Пользователей не касается, что для того, чтобы удовлетво­рить капризам языка C++, классы Array2D должны быть синтаксически совмес­тимы с одномерными массивами.Каждый объект ArraylD обозначает одномерный массив, отсутствующий в аб­страктной модели, применяемой пользователями класса Array2D.

 

Различение записи и чтения в функции operator[]

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

Но наиболее известным применением proxy-классов является различение чтения и записи в функции operator[].

Функция operator [ ] может вызываться как для чте­ния, так и для записи. При чтении оператор стоит справа от оператора присваивания, при записи - слева. Использование объекта слева от оператора присваивания (как lvalue) означает, что он может изменяться, ис­пользование его справа (как rvalue) - что он не может быть изменен.

Так как реализация чтения, в особенности для структур данных со счетчиком ссылок, требует намного меньших усилий, чем реализация записи, хотелось бы различать использование функции operator [ ] слева и справа от оператора при­сваивания. В С++ не существует способа определить контекст вы­зова operator [ ] внутри самой функции, то есть невозможно различить ее использование как lvalue и rvalue.

Различить использование operator [ ] слева и справа от оператора присваивания в самой функции нельзя, однако ничто не мешает по-разному обрабатывать чтение и запись, если отложить действия до тех пор, пока не будет видно, как используется результат функции operator [ ]. Все что нужно - отсро­чить решение о том, будет ли выполняться чтение или запись объекта, до тех пор пока не произойдет возврат из вызова функции operator [ ].

Proxy-класс позволяет получить нужный выигрыш во времени, поскольку функцию operator [ ] можно изменить так, чтобы она возвращала proxy-объект. Затем надо подождать и посмотреть, как этот proxy-объект будет использоваться. Если он считывается, значит, вызов функции
operator [ ] следует рассматривать как чтение, если записывается - как запись.

(Более подробно смотри Скот Мейерс Наиболее эффективное использование С++).

 

3 Порядок виконання роботи

 

4 Контрольні запитання та завдання

 

5 Завдання

 

Реализовать динамический массив в виде Proxy – класса для решения следующих задач используя контрольный пример .

Необходимо перегрузить оператор “=”.

 

6 Варіанти індивідуальних завдань

 

1. Знайти найменші елементи у кожному рядку матриці та номер максимального з них.

2. Відсортувати по зростанню перший рядок та другий стовпець матриці.

3. Знайти найбільші елементи у кожному стовпці матриці та номер найменшого серед них.

4. Знайти суми кожного рядка матриці та найменшу серед них.

5. Серед елементів матриці, що знаходяться вище головної діагоналі, знайти добуток парних елементів.

6. Знайти суму додатніх непарних елементів матриці, що стоять нижче побічної діагоналі.

7. Визначити, скільки елементів матриці в рядках з парними номерами перевищують відношення максимального елемента до мінімального?

8. Відсортувати за зростанням добутки від’ємних елементів рядків матриці.

9. Відсортувати по зменшенню масив максимальних елементів стовпців матриці.

10. У матриці знайти суму парних елементів, що лежать вище головної діагоналі. Якщо вона ділиться на 3, обнулити побічну діагональ.

11.У матриці відсортувати за зростанням елементи головної діагоналі та поміняти місцями максимальний елемент з мінімальним.

12. Переставити рядки матриці відповідно до зростання елементів другого стовпця.

13. Знайти мінімальний елемент матриці, і якщо він парний та парна строка його розташування — відсортувати третій стовпець матриці.

14. Переставити стовпці матриці у відповідності до зростання елементів третього рядка.

15. У кожному рядку матриці знайти кількість елементів, що діляться на 3, та відсортувати ці значення з находженням екстремумів.

16. У матриці в рядках з від’ємним елементом на головній діагоналі знайти найбільший елемент рядка та мінімум серед них.

17. У матриці замінити нулями всі від’ємні елементи над головною діагоналлю. Знайти місце максимуму серед елементів нижче побічної діагоналі.

18. Переписати до масиву В всі елементи матриці А, більші значення x. Якщо в черговому рядку таких немає, записувати до В значення 0.

19. Переписати до масиву С всі значення матриці D, менші заданого у та знайти добуток цих елементів і розташувати їх за зростанням.

20. У вигляді матриці задано таблицю футбольного чемпіонату. Визначити, у скількох команд кількість виграшів перевищує кількість поразок.

21. Написати програму сортування команд за зменшенням кількості перемог, використовуючи таблицю футбольного чемпіонату.

22. Знайти максимальний елемент матриці, і якщо його номер стовпця непарний, то відсортувати цей стовпець.

23. Вихідну матрицю відсортувати за зростанням кількісті додатних елементів у стовпцях.

24. Серед елементів матриці нижче побічної діагоналі відібрати ті, що перевищують максимум у другому стовпці матриці.

25. У квадратній матриці провести сортування тих рядків, у яких на побічній діагоналі стоїть парне число.

26. У стовпцях матриці знайти максимуми та відсортувати стовпці за зменшенням.

27. Переставити стовпці матриці відповідно до зростання елементів другого рядка.

28. Знайти добутки діагоналей квадратної матриці. Відсортувати перший рядок за зростанням.

29. Задано дві матриці розміром 3*3. Перемножити їх за правилом "рядок на стовпець".

30. Знайти скалярні добутки першого рядка матриці на всі інші.

 

 


7 Контрольний приклад

 

// proxy.cpp : Defines the entry point for the console application.

//

#include "stdafx.h"

#include <iostream>

using namespace std;

template <class T>

class Array2D

{

public:

class ArraylD

{

private:

int dim2;

T * Array1;

public:

friend class Array2D ;

ArraylD():Array1(NULL),dim2(0) {}

T& operator[](int index);

const T& operator[] (int index) const;

}; //class ArraylD

private:

int dim1;

ArraylD* Array2;

public:

Array2D():dim1(0),Array2(NULL){};

Array2D(int d1, int d2);

virtual ~Array2D();

ArraylD& operator[] (int index)

{

return Array2[index];

}

const ArraylD& operator[] (int index) const

{

return Array2[index];

}

};

int main()

{

int n(3),m(4);

Array2D<int> array2D(n,m);

for(int i = 0; i< n ;cout<<endl,++i)

for(int j = 0; j< m ;++j)

{

array2D[i][j] = rand()%11;

cout<<array2D[i][j]<<'\t';

}

cin.get();

}

 

template <class T>

T& Array2D<T>::ArraylD::operator[](int index)

{

return Array1[index];

}

template <class T>

const T& Array2D<T>::ArraylD::operator[](int index)const

{

return Array1[index];

}

template <class T>

Array2D<T>::Array2D(int d1, int d2)

{

dim1 = d1;

Array2 = new ArraylD[dim1];

for (int i(0);i<d1;++i)

{

Array2[i].dim2 = d2;

Array2[i].Array1 = new T [d2];

}

}

template <class T>

Array2D<T>::~Array2D()

{

for (int i(0);i<dim1;++i)

{

delete[]Array2[i].Array1;

}

delete[] Array2;

}