Указатель this
Конкретные переменные типа "класс" называются экземплярами класса, или объектами. Каждый объект содержит свой экземпляр полей класса. Методы класса находятся в памяти в единственном экземпляре и используются всеми объектами совместно, поэтому необходимо обеспечить работу методов с полями именно того объекта, для которого они были вызваны. Это обеспечивается передачей в функцию скрытого параметра this, в котором хранится константный указатель на вызвавший функцию объект. Указатель this неявно используется внутри метода для ссылок на элементы объекта. В явном виде этот указатель применяется в основном для возвращения из метода указателя (return this;) или ссылки (return *this;) на вызвавший объект.
ЗАДАЧА 3.1. Для иллюстрации использования указателя this добавим метод сложения в класс complex.
class complex //Определяем класс complex
{
//Закрытые поля класса и метод
double x;
double y;
void show_complex();
//Открытые методы
public:
void vvod();
complex add(complex a);
};
void complex::show_complex()
{
if (y>=0)
cout<<x<<"+"<<y<<"i"<<endl; // неявное использование указателя this
else cout<<x<<y<<"i"<<endl; // неявное использование указателя this
}
void complex::vvod()
{
cout<<"Vvedite x\t"; cin>>x; // неявное использование указателя this
cout<<"Vvedite y\t"; cin>>y; // неявное использование указателя this
}
complex complex:: add(complex a)
{
complex res;
res.x=x+a.x; // неявное использование указателя this
res.y=y+a.y; // неявное использование указателя this
return this; // явное использование указателя this
}
int main()
{
complex chislo1, chislo2;
chislo1.vvod(); chislo2.vvod();
cout<<"Summa kompleksnih chisel="<<chislo1.add(chislo2);
return 0;
}
В предыдущем примере метод chislo.vvod() использовался для присвоения начального значения некоторым членам класса, однако для упрощения процесса инициализации объекта предусмотрена специальная функция, которая называется конструктором. Имя конструктора совпадает с именем класса. Конструктор предназначен для инициализации объекта и запускается автоматически при создании экземпляра класса (при объявлении переменной типа class).
. Ниже перечислены основные свойства конструкторов.
· Конструктор не возвращает значение, даже типа void.
· Класс может иметь несколько конструкторов с разными параметрами для разных видов инициализации (при этом используется механизм перегрузки).
· Конструктор, вызываемый без параметров, называется конструктором по умолчанию.
· Параметры конструктора могут иметь любой тип, кроме этого же класса. Можно задавать значения параметров по умолчанию. Их может содержать только один из конструкторов.
· Если программист не указал ни одного конструктора, компилятор создает его автоматически. Такой конструктор вызывает конструкторы по умолчанию для полей класса. В случае, когда класс содержит константы или ссылки, при попытке создания объекта класса будет выдана ошибка, поскольку их необходимо инициализировать конкретными значениями, а конструктор по умолчанию этого делать не умеет.
· Конструкторы не наследуются.
· Конструкторы нельзя описывать с модификаторами const, virtual и static.
· Конструкторы глобальных объектов вызываются до вызова функции main. Локальные объекты создаются, как только становится активной область их действия. Конструктор запускается и при создании временного объекта (например, при передаче объекта из функции).
· Конструктор вызывается, если в программе встретилась какая-либо из синтаксических конструкций:
имя_класса имя_объекта [(список параметров)];
// Список параметров не должен быть пустым
имя_класса (список параметров);
// Создается объект без имени (список может быть пустым)
имя_класса имя_объекта = выражение;
// Создается объект без имени и копируется
Примеры:
complex S (200, 300), V(50), Z;
complex X = complex (1000);
complex Y = 500;
В первом операторе создаются три объекта. Значения не указанных параметров устанавливаются по умолчанию.
Во втором операторе создается безымянный объект со значением параметра x = 1000 (значение второго параметра устанавливается по умолчанию). Выделяется память под объект Х, в которую копируется безымянный объект.
В последнем операторе создается безымянный объект со значением параметра x = 500 (значение второго параметра устанавливается по умолчанию). Выделяется память под объект Y, в которую копируется безымянный объект. Такая форма создания объекта возможна в том случае, если для инициализации объекта допускается задать один параметр.
ЗАДАЧА 3.2. Добавим в созданный в предыдущем примере класс complex конструктор:
#include <iostream>
#include <string>
#include <math.h>
const double PI=3.14159;
using namespace std;
//Объявляем класс complex. Внутри класса указаны, только прототипы методов,
//а сами функции описаны за пределами класса.
class complex
{
double x;
double y;
void show_complex();
public:
//Прототип конструктора класса.
complex();
double modul();
};
complex::complex()
{
cout<<"Vvedite x\t"; cin>>x;
cout<<"Vvedite y\t"; cin>>y;
}
double complex::modul()
{
return pow(x*x+y*y,0.5);
}
void complex::show_complex()
{
if (y>=0) cout<<x<<"+"<<y<<"i"<<endl;
else cout<<x<<y<<"i"<<endl;
}
int main()
{
//Описываем экземпляр класса, при выполнении программы после создания переменной
//автоматически вызывается констуктор.
complex chislo;
chislo.show_complex();
cout<<"Modul kompleksnogo chisla="<<chislo.modul();
return 1;
}
Если члены класса, являются массивами (указателями), то в конструкторе логично предусмотреть выделение памяти.
ЗАДАЧА 3.3. С использованием классов решить следующую задачу. Заданы координаты n точек в k-мерном пространстве. Найти точки, расстояние между которыми наибольшее и наименьшее.
Для решения задачи создадим класс prostr.
Члены класса:
• int n – количество точек;
• int k – размерность пространства;
• double **a – матрица, в которой будут храниться координаты точек, a[i][j] - i-я координата точки с номером j.
• double min – минимальное расстояние между точками в k-мерном пространстве;
• double max – максимальное расстояние между точками в k-мерном пространстве;
• int imin, int jmin – точки, расстояние между которыми минимально;
• int imax, int jmax – точки, расстояние между которыми максимально.
Методы класса:
• prostr() – конструктор класса, в котором определяются n – количество точек, k – размерность пространства, выделяется память для матрицы a координат точки и вводятся координаты точек;
• poisk_max() – функция нахождения точек, расстояние между которыми наибольшее;
• poisk_min() – функция нахождения точек, расстояние между которыми наименьшее;
• vivod_result() – функция вывода результатов: значений min, max, imin, jmin, imax, jmax;
• delete_a() – освобождение памяти выделенной для матрицы a.
В главной программе необходимо будет описать экземпляр класса и
последовательно вызвать методы poisk_min(), poisk_max(), vivod_result(), delete_a().
Текст программы:
#include <iostream>
#include <math.h>
using namespace std;
class prostr{
//Все члены класса – закрытые.
int n;
int k;
double **a;
double min;
double max;
int imin;
int jmin;
int imax;
int jmax;
//Открытые методы класса.
public:
prostr();
void poisk_min();
void poisk_max();
int vivod_result();
int delete_a();
};
prostr::prostr()
{
int i,j;
cout<<"VVedite razmernost prostrantva ";
cin>>k;
cout<<"VVedite kolichestvo tochek ";
cin>>n;
a=new double*[k];
for(i=0;i<k;i++)
a[i]=new double[n];
for(j=0;j<n;j++)
{
cout<<"VVedite koordinati "<<j<<" tochki"<<endl;
for(i=0;i<k;i++)
cin>>a[i][j];
}
}
void prostr::poisk_max()
{
int i,j,l;
double s;
for(max=0,l=0;l<k;l++)
max+=(a[l][0]-a[l][1])*(a[l][0]-a[l][1]);
max=pow(max,0.5);
imax=0;jmax=1;
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
{
for(s=0,l=0;l<k;l++)
s+=(a[l][i]-a[l][j])*(a[l][i]-a[l][j]);
s=pow(s,0.5);
if (s>max)
{
max=s;
imax=i;
jmax=j;
}
}
}
void prostr::poisk_min()
{
int i,j,l;
double s;
for(min=0,l=0;l<k;l++)
min+=(a[l][0]-a[l][1])*(a[l][0]-a[l][1]);
min=pow(min,0.5);
imin=0;jmin=1;
for(i=0;i<k;i++)
for(j=i+1;j<n;j++)
{
for(s=0,l=0;l<k;l++)
s+=(a[l][i]-a[l][j])*(a[l][i]-a[l][j]);
s=pow(s,0.5);
if (s<min)
{
min=s;
imin=i;
jmin=j;
}
}
}
void prostr::vivod_result()
{
int i,j;
for(i=0;i<k;cout<<endl,i++)
for (j=0;j<n;j++)
cout<<a[i][j]<<"\t";
cout<<"max="<<max<<"\t nomera "<<imax<<"\t"<<jmax<<endl;
cout<<"min="<<min<<"\t nomera "<<imin<<"\t"<<jmin<<endl;
}
void prostr::delete_a()
{
delete [] a;
}
void main()
{
prostr x; //Описание переменной - экземпляра класса prostr.
//Вызов метода poisk_max для поиска максимального расстояния между
//точками в k-мерном пространстве;
x.poisk_max();
//Вызов метода poisk_min для поиска минимального расстояния между
//точками в k-мерном пространстве;
x.poisk_min();
//Вызов метода vivod_result для вывода результатов
x.vivod_result();
//Вызов функции delete_a.
x.delete_a();
}
Результаты работы программы:
VVedite razmernost prostrantva 2
VVedite kolichestvo tochek 4
VVedite koordinati 0 tochki
1 2
VVedite koordinati 1 tochki
2 3
VVedite koordinati 2 tochki
4 5
VVedite koordinati 3 tochki
-7 -9
1 2 4 -7
2 3 5 -9
max=17.8045 nomera 2 3
min=1.41421 nomera 0 1