Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Комментарии к программе 2.4.

Задание к программе 1.1

Упражнения:

1) выпишите сообщение, которое выдает компилятор при попытке доступа к закрытым членам класса;

2) примените к классу операцию sizeof и объясните результат.

Задания:

Первый вариант:

1. Доработать конструктор таким образом, чтобы он выполнял проверку на правильность задания координат: x1 должно быть меньше x2, а y1 – меньше y2.

2. Разработать класс CIRCLE (Круг). Конструктор должен инициализировать координаты концов радиуса круга. Класс должен иметь методы вычисления площади и длины круга.

Второй вариант:

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

2. Разработать класс "Прямоугольный треугольник" TRIANGLE. Конструктор должен инициализировать координаты трех вершин треугольника, причем, координаты второй вершины должны соответствовать вершине с прямым углом. Класс должен иметь закрытый метод вычисления сторон треугольника и открытые методы вычисления площади и периметра треугольника.

 

Программа 1.2. В программе демонстрируется пример класса для создания матриц в динамической памяти. Используется конструктор и деструктор для создания экземпляров класса и указателя на них. Конструктор выполнен как функция с умалчиваемыми значениями параметров. Матрица моделируется с помощью одномерного массива.

 

#include <conio.h>

#include <stdlib.h>

#include <iostream.h>

#define size unsigned char

 

class Matrix{

size m,n; //Размеры матрицы

double *matr;

public:

Matrix(size, size=1); //Прототип конструктора

~Matrix() //Деструктор

{delete [] matr;}

void display(); //Прототип метода

};

 

Matrix::Matrix(size M, size N)

{

randomize();

m=M; n=N;

if((matr=new double[n*m])==NULL)

exit(1);

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

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

*(matr+i*n+j)=random(1000)*0.01;

}

void Matrix::display()

{

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

{

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

{

cout.width(7);

cout<< *(matr+i*n+j);

}

cout<<"\n";

}

cout<<"\n";

cout<<"Press any key...\n";

getch();

}

 

int main()

{

clrscr();

Matrix A(2,2),B(4,5),*pMatr=&B;

Matrix Vec(5);

cout<<"The matrix A:\n";

A.display();

cout<<"The matrix B:\n";

pMatr->display(); //Доступ через указатель

cout<<"The vector Vec:\n";

Vec.display();

return 0;

}

Задание к программе 1.2

Упражнения:

1) показать использование указателя pMatr для доступа к элементам вектора Vec;

2) реализуйте деструктор вне описания класса;

3) разработайте метод класса, позволяющий вводить элементы матрицы с клавиатуры.

Задания:

Первый вариант:

1. Разработать метод класса для вычисления произведения всех элементов матрицы.

2. *Разработать метод класса для вычисления максимального элемента матрицы.

Второй вариант:

1. Разработать метод класса для вычисления суммы всех элементов матрицы.

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

 

*Программа 1.3. В программе демонстрируется создание массива экземпляров класса Worker (Работник) с использованием конструктора с параметрами и правила применения статического члена класса MoneyOfFirm (Капитал фирмы). Метод класса work() увеличивает количество денег у работника и капитал фирмы в зависимости от продолжительности работы (period).

 

#include <iostream.h>

#include <conio.h>

 

class Worker{

float MoneyOfWorker;

static float MoneyOfFirm; //Статический член класса

public:

Worker(float m) {MoneyOfWorker=m;}

void work(float);

void display() {cout<<MoneyOfWorker<<endl;}

void displayMoneyOfFirm() {cout<<MoneyOfFirm<<endl;}

};

 

void Worker::work(float period)

{

MoneyOfWorker+=2*period;

MoneyOfFirm+=10*period;

}

 

float Worker::MoneyOfFirm=1000; //Инициализация статического компонента

 

int main()

{

clrscr();

const n=5;

Worker M[n]={50,28,35,45,49}; //Создание массива экземпляров //класса и их инициализация

cout<<"Начальное количество денег у работников:\n";

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

M[i].display();

cout<<"Начальный капитал фирмы:\n";

M[0].displayMoneyOfFirm();

cout<<"Конечное количество денег у работников:\n";

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

{

M[i].work(2);

M[i].display();

}

cout<<"Конечный капитал фирмы:\n";

M[0].displayMoneyOfFirm();

getch();

return 0;

}

 

*Задание к программе 1.3

Упражнения:

1) попробуйте получить доступ к статическому члену класса через экземпляр M[1];

2) продемонстрируйте доступ к членам класса через указатель на класс;

3) оформите определение класса в виде заголовочного файла worker.h, реализацию методов класса ‑ в виде файла worker.cpp, а главную функцию ‑ в виде файла prog3.cpp. Создать проект prog3.prj, в который включить файлы worker.cpp и prog3.cpp и выполнить многофайловую компиляцию.

 

Задания:

Первый вариант. Доработать методы и конструктор класса Worker таким образом, чтобы можно было задавать и учитывать производительность каждого из создаваемых объектов типа Worker. Определение конструктора сделать внешним (вне тела класса).

Второй вариант. Доработать класс Worker, введя в него еще один метод ‑ rest() (Отдых), который уменьшает количество денег у работника в зависимости от продолжительности отдыха. Определение метода display()сделать внешним (вне тела класса).

 

*Программа 1.4. В программе создан класс RECTANGLE (Прямоугольник), в котором реализованы методы вывода графического изображения прямоугольника, "стирания" его с экрана и перемещения. Для работы программы скопируйте в текущий директорий файл egavga.bgi из директория BGI пакета Borland C++v.3.1.

#include <conio.h>

#include <stdlib.h>

#include <graphics.h>

#include <iostream.h>

 

class RECTANGLE{

int left,top,right,bottom;

public:

RECTANGLE(int,int,int,int); //Конструктор

void show(); //Метод вывода изображения

void hide(); //Метод скрытия изображения

void move(int,int); //Метод перемещения изображения

};

 

RECTANGLE::RECTANGLE(int x1,int y1,int x2,int y2)

{

left=x1;

right=x2;

top=y1;

bottom=y2;

}

void RECTANGLE::show()

{

setcolor(LIGHTGREEN); //Функция установки цвета

rectangle(left,top,right,bottom);//Функция вывода фигуры

}

void RECTANGLE::hide()

{

setcolor(getbkcolor());

rectangle(left,top,right,bottom);

}

void RECTANGLE::move(int dx,int dy)

{

hide();

left+=dx; right+=dx;

top+=dy; bottom+=dy;

show();

}

int main()

{

int gdriver=DETECT,gmode,errorcode;

initgraph(&gdriver,&gmode,"");

errorcode=graphresult();

if(errorcode!=grOk)

{

cout<<"Graphics error:\n"

cout<<grapherrormsg(errorcode)<<endl;

cout<<"Press any key to halt\n";

getch();

exit(1);

}

int xmax=getmaxx();

int ymax=getmaxy();

RECTANGLE a(10,20,50,30);

a.show();

outtextxy(xmax/2,ymax-ymax/10,"Press any key...");

getch();

a.hide();

a.move(10,20);

getch();

a.move(100,100);

getch();

closegraph();

return 0;

}

 

*Задание к программе 1.4

Разработать метод класса extend(), который увеличивает площадь прямоугольника. Для демонстрации метода реализуйте в главной функции код, который в начале работы выводит прямоугольник в центре экрана, а затем постепенно увеличивает его до размеров экрана.

2. Контрольные вопросы к лабораторной работе №1

1. Что такое класс в языке С++? Для чего она применяется?

2. Дайте определения конструктора и деструктора класса.

3. Найдите ошибку:

В классе PRIMER объявлен прототип int PRIMER(int a, float pi);

4. Найдите ошибки:

class ABC{

int a=3;

int b;

int c;

public:

ABC(int n=1) {b=n;}

mul() {c=1+a*b;}

};

5. Можно ли в классе Matrix из программы 1.2 вместо существующего конструктора применить перегруженные конструкторы, если да, то как?

6. В каком случае значение одного объекта можно присвоить другому объекту.

7. Создайте класс RECTANGLE в программе 1.1 с помощью ключевого слова struct.

8. Чем отличаются статические члены класса от обычных?

9. Почему в приведенных выше классах не использовалось ключевое слово private?

10. Придумайте члены-функции доступа к защищенным членам класса Matrix. из программы 1.2.

11. Приведите примеры непосредственного доступа и доступа через указатель к членам-данным и членам-функциям экземпляра класса, являющегося элементом массива.

 


Объектно-ориентированное программирование

Лабораторная работа №2

Дружественные функции, перегрузка операций

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

1. Задание к лабораторной работе

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

 

#include <iostream.h>

#define pi 3.14159

class Rectangle; //Предварительное объявление класса

class Circle{

float S;

float R;

void area() {S=pi*R*R;}

friend float sumS(Rectangle,Circle);//Объявление "дружественности"

public:

Circle(float r) {R=r;}

};

 

class Rectangle{

float a,b;

float S;

void area() {S=a*b;}

friend float sumS(Rectangle,Circle); //Объявление "дружественности"

public:

Rectangle(float length,float width) {a=length;b=width;}

};

 

float sumS(Rectangle ro, Circle co) //Определение дружественной

{ //функции

ro.area();

co.area();

return ro.S+co.S;

}

 

int main()

{

Circle c(1.0);

Rectangle r(2.0,3.0);

cout<<"Суммарная площадь фигур: "<<sumS(r,c)<<endl;

return 0;

}

 

Задание к программе 2.1

Упражнения:

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

2. *Разработайте перегруженную дружественную функцию, в которую передаются указатели на объекты класса.

Задания:

Первый вариант: Добавить в программу класс Triangle (Треугольник) и разработать дружественную функцию, которая выводит на печать наименование фигуры (Rectangle, Circle или Triangle), площадь которой больше.

Второй вариант: Добавить в программу класс Triangle (Треугольник) и разработать дружественную функцию, которая выводит на печать наименование фигуры (Rectangle, Circle или Triangle), периметр (длина окружности) которой больше.

 

Программа 2.2. Программа, в которой созданы два класса OUT_AMP (Выходной усилитель) и PRE_AMP (Предварительный усилитель). Усилители имеют параметры: I – ток потребления и K ‑ коэффициент усиления. Функция float isum(PRE_AMP *) const является членом класса OUT_AMP и одновременно объявлена дружественной для класса PRE_AMP. Модификатор const указывает, что эта функция не может менять значения членов класса. Функция вычисляет суммарный ток потребления усилительного устройства, состоящего из нескольких предварительных усилителей и одного выходного усилителя.

 

#include <iostream.h>

#define n 3

class PRE_AMP;

class OUT_AMP{

float K;

float I;

public:

float isum(PRE_AMP *) const;

OUT_AMP(float a,float b)

{K=a; I=b;}

};

 

class PRE_AMP{

float K;

float I;

static int count;

friend float OUT_AMP::isum(PRE_AMP *) const;

public:

void setKI(float,float);

PRE_AMP();

};

 

int PRE_AMP::count=0;

 

PRE_AMP::PRE_AMP()

{++count;}

 

void PRE_AMP::setKI(float a,float b)

{K=a; I=b;}

 

float OUT_AMP::isum(PRE_AMP *obj) const

{

float sum=0.0;

for(int i=0;i<PRE_AMP::count;i++)

sum+=obj[i].I;

return sum+I;

}

 

int main()

{

OUT_AMP oa(3,10);

PRE_AMP pa[n];

float a,b;

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

{

cout<<"Введите Ку и Iп "<<i+1<<"-го предусилителя"<<endl;

cin>>a>>b;

pa[i].setKI(a,b);

}

cout<<"Суммарный ток потребления: "<<oa.isum(pa)<<endl;

return 0;

}

 

Задание к программе 2.2

Упражнения:

1. Закомментируйте первую строку программы (class PRE_AMP;), запустите компилятор и объясните сообщения об ошибках.

2. Создайте динамический массив из n предусилителей, пользуясь операторами new и delete.

Задание (общее)

1. Создайте функцию-член класса OUT_AMP, которая является дружественной для класса PRE_AMP и вычисляет общий коэффициент усиления (произведение всех коэффициентов усиления) устройства.

2. Создайте дружественную функцию для классов OUT_AMP и PRE_AMP, которая не является членом этих классов и вычисляет общее число транзисторов усилительного устройства. Параметр "число транзисторов" ввести в классы.

 

Программа 2.3. Программа, в которой реализован простейший пример перегрузки операции суммирования.

 

#include <iostream.h>

#include <stdlib.h>

 

class Matrix{

int m[2][2];

public:

Matrix(int=0); //Конструктор с умалчиваемым значением параметра

void display();

Matrix operator+(Matrix); //Прототип функции-оператора

};

 

void Matrix::display()

{

cout<<m[0][0]<<' '<<m[0][1]<<endl;

cout<<m[1][0]<<' '<<m[1][1]<<endl;

}

Matrix::Matrix(int C)

{

for(int i=0;i<2;i++)

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

m[i][j]=random(C);

}

Matrix Matrix::operator+(Matrix ob)

{

Matrix tmp(2);

for(int i=0;i<2;i++)

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

tmp.m[i][j]=m[i][j]+ob.m[i][j];

return tmp;

}

 

int main()

{

randomize();

Matrix a(50),b(30),c;

c=a+b;

a.display();

b.display();

c.display();

return 0;

}

 

Задание к программе 2.3

Первый вариант: Создать перегруженные операции: сложения элементов матрицы с целым числом (использовать знак операции "+") и вычисления определителя матрицы (обозначить значком "!").

Второй вариант: Создать перегруженные операции: умножения элементов матрицы на целое число и умножения матриц (использовать знак операции "*").

 

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

 

#include <iostream.h>

#include <stdlib.h>

class Array{

int n;

int *p;

static int count;

public:

void show();

Array operator+(Array &);

void ERRMEM();

Array(const Array &); //Конструктор копии

Array(int=0); //Конструктор с умалчиваемым значением

~Array();

};

 

int Array::count=0; //Инициализация статического члена

Array::Array(int i) //Определение конструктора

{ //с умалчиваемым значением

++count;

n=i;

if(n!=0)

{

p=new int[n];

if(!p) ERRMEM();

cout<<"Введите элементы массива "<<count<<endl;

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

cin>>p[i];

}

}

 

Array::Array(const Array &ob) //Определение конструктора

{ //копирования

++count;

n=ob.n;

p=new int [n];

if(!p) ERRMEM();

for(int i=0;i<ob.n;i++)

p[i]=ob.p[i];

}

 

void Array::ERRMEM()

{

cout<<"Ошибка выделения памяти"<<endl;

exit(1);

}

 

Array::~Array()

{

delete [] p;

}

 

void Array::show()

{

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

cout<<p[i]<<' ';

cout<<endl;

}

 

Array Array::operator+(Array &ob)

{

if(n!=ob.n)

{

cout<<"Ошибка: Размеры массивов не совпадают"<<endl;

exit(2);

}

Array tmp=ob; //Сработает конструктор копирования

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

tmp.p[i]+=p[i];

return tmp;

}

 

int main()

{

Array a(3),b(3),c;

cout<<"a: ";

a.show();

cout<<"b: ";

b.show();

c=a+b;

cout<<"c: ";

c.show();

return 0;

}

 

Комментарии к программе 2.4.

1. Если в теле перегруженной операции создать временный объект (Array tmp;), то создастся объект с нулевым количеством элементов. Поэтому сумму подсчитать будет невозможно.

2. Если в теле перегруженной операции создать временный объект (Array tmp(n);) с числом элементов n, то для него из-за содержания конструктора необходимо будет вводить элементы с клавиатуры, а это нецелесообразно и неудобно.

3. Если записать так:

Array tmp;

tmp=ob;

то после операции присвоения указатели у обоих объектов будут равны и после срабатывания деструктора для tmp разрушится указатель на область динамической памяти и для объекта tmp и для объекта ob.

4. По причине выше изложенного, разработан специальный конструктор копирования, который срабатывает только при инициализации. В перегруженной функции-операторе создается объект tmp и инициализируется (Array tmp=ob;). При этом, благодаря конструктору копирования, для объекта tmp создается собственная область динамической памяти, в которую заносятся данные из динамической области копируемого объекта (инициализатора), в данном случае объекта ob. При возвращении из функции-оператора срабатывает деструктор объекта tmp, который освобождает его динамическую память.

5. Поскольку объект ob передается в функцию-оператор по ссылке, его копия не создается и деструктор этого объекта не срабатывает.

 

*Задание к программе 2.4

Упражнения:

1. Вставьте отладочную печать в конструктор, конструктор копирования и деструктор. Подсчитайте число их вызовов и объясните результат.

2. Закомментируйте прототип и определение конструктора копии и запустите программу на исполнение, объясните результат.

3. Проверьте, работает ли перегруженная операция для трех массивов (d=a+b+c;).

Задание (общее)

 

1. Разработайте перегруженную операцию вычитания массивов.

2. Разработайте перегруженную операцию вычисления скалярного произведения векторов (компонентами вектора являются элементы массива).

3. Разработайте дружественную перегруженную операцию суммирования массивов.

2. Контрольные вопросы к лабораторной работе №2

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

2. В чем отличие дружественной функции-члена класса от дружественной функции, не являющейся членом класса?

3. В каком месте определения класса можно объявлять дружественность функции? Привести пример.

4. Можно ли создавать перегруженные дружественные функции? Привести пример.

5. Как сделать предварительное объявление класса и для чего это необходимо?

6. Как обеспечивается доступ к элементам класса в дружественных функциях?

7. Приведите собственные примеры перегрузки операций.

8. Перечислить операции языка С++ которые нельзя сделать перегруженными.

9. *Приведите пример определения и инициализировать статический член класса.

10. *Дайте определение ссылки. В чем отличие ссылки от указателя?

11. *Дайте определение конструктора копирования.

 


Объектно-ориентированное программирование

Лабораторная работа №3

Наследование

Цель работы – изучить простейшие элементы наследования в языке С++, научиться создавать производные классы с множественным наследованием.

1. Задание к лабораторной работе

Программа 3.1. Программа демонстрирует назначение и синтаксис оформления простого наследования и множественного наследования классов. Ниже приведена схема иерархии наследования. Для наглядности исходного текста программы, она разбита на несколько модулей. При компиляции и линковке удобно все модули поместить в один каталог. Для предотвращения возможного включения текста заголовочных файлов в программу более одного раза применяются директивы #ifndef (если не определен), #define, #endif.

 

 

Рис.1. Иерархия наследования классов

 

//Файл univer.h ***Класс УНИВЕРСИТЕТ***

#ifndef _UNIVER_H

#define _UNIVER_H

 

#include <iostream.h>

 

class University{

char nameUniversity[40]; //Наименование

public:

void set_University();

void show_University() {cout<<nameUniversity;}

char *get_University() {return nameUniversity;}

};

 

void University::set_University()

{

cout<<"Введите название университета: ";

cin>>nameUniversity;

}

#endif

 

//Файл faculty.h ***Класс ФАКУЛЬТЕТ***

#ifndef _FACULTY_H

#define _FACULTY_H

#include <iostream.h>

 

#include "univer.h"

 

class Faculty: public University{

char nameFaculty[40];

public:

void set_Faculty();

void show_Faculty() {cout<<nameFaculty;}

char *get_Faculty() {return nameFaculty;}

};

 

void Faculty::set_Faculty()

{

cout<<"Введите название факультета: ";

cin>>nameFaculty;

}

 

#endif

 

//Файл group.h ***Класс ГРУППА***

#ifndef _GROUP_H

#define _GROUP_H

#include <iostream.h>

 

#include "faculty.h"

 

class Group: public Faculty{

int numberGroup;

public:

void set_Group();

int get_Group() {return numberGroup;}

};

 

void Group::set_Group()

{

cout<<"Введите номер группы: ";

cin>>numberGroup;

}

 

#endif

 

//Файл lab3.cpp

#include <iostream.h>

 

#include "group.h"

 

class Man{ //класс "ЧЕЛОВЕК"

char name[40]; //Имя

int age; //Возраст

char sex; //Пол

public:

void set_nameMan() {cout<<"Введите фамилию: "; cin>>name;}

char *get_nameMan() {return name;}

void set_dataMan();

void show_dataMan();

};

 

class Student: public Man, public Group{

int year; //Год обучения

long number; //Номер зачетной книжки

public:

void set_dataStudent();

void show_dataStudent();

};

 

void Man::set_dataMan()

{

set_nameMan();

cout<<"возраст: "; cin>>age;

cout<<"пол (м/ж): "; cin>>sex;

}

 

void Man::show_dataMan()

{

cout<<get_nameMan()<<" "<<age<<" "<<sex<<endl;

}

 

void Student::set_dataStudent()

{

set_University();

set_Faculty();

set_Group();

set_dataMan();

cout<<"Введите год обучения:"; cin>>year;

cout<<"номер зачетной книжки: "; cin>>number;

}

 

void Student::show_dataStudent()

{

cout<<endl;

cout<<get_University()<<" Факультет "<<get_Faculty()<<endl;

cout<<"Группа "<<get_Group()<<" "<<year<<" курс "<<endl;

show_dataMan();

cout<<"Номер зачетной книжки "<<number<<endl;

}

 

int main()

{

Student st;

st.set_dataStudent();

st.show_dataStudent();

return 0;

}

 

Задание к программе 3.1

Упражнения:

1. Поместите определение класса Man и реализации его методов в дополнительный заголовочный файл.

2. Создайте массив экземпляров класса объектов Student и продемонстрируйте в функции main() работу с ним с помощью цикла.

3. Удалите в определении класса Student наследование от класса Group, запустите компиляцию и объясните сообщения об ошибках.

4. Сделайте метод set_University() в классе University закрытым и попытайтесь откомпилировать программу, прокомментируйте сообщения об ошибках.

5. Создайте экземпляры классов "Университет", Факультет", "Группа", "Человек", покажите доступ к их компонентам.

Задания:

Первый вариант: Создайте производный класс "Участник игры КВН", наследующий классы "Факультет" и "Человек". Класс должен содержать собственную компоненту "Наименование команды" и функцию ее ввода. Класс должен иметь функцию вывода на печать наименования команды, названия факультета и фамилии игрока. Нарисуйте в отчете схему наследования, аналогичную приведенной.

Второй вариант: Создайте производный класс "Проездной билет", наследующий классы "Университет" и "Человек". Класс должен содержать собственную компоненту "Номер билета" и функцию ее ввода. Класс должен иметь функцию вывода на печать номера билета, названия университета и фамилии владельца билета. Нарисуйте в отчете схему наследования, аналогичную приведенной.

*Общее задание: Придумайте собственный пример наследования.

2. Контрольные вопросы к лабораторной работе №3

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

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

3. Как сделать компоненты базового класса доступными в производном классе, но недоступными вне классов?

4. Укажите ошибки и исправьте их в примере:

#include <iostream.h>

class B{

int b;

public:

void setb() {cin>>b;}

};

class C: private B{

int c;

public:

void setc() {setb(); cin>>c;}

void show() {cout<<b<<c;}

};

int main()

{

C ob;

ob.setb();

ob.setc();

ob.show();

return 0;

}

 

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...