ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ



Классы

Сначала программирование было только процедурным. Но затем, чем больше и крупнее становились проекты, программы, тем больше появилась необходимость в изобретении такой вещи как классы и объектно-ориентированного программирования в целом.

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

Класс- это свой собственный тип данных. Мы уже знаем примитивные встроенные типы данных- int, double, char, bool и прочие. Но можно создавать и свои типы данных, а потом с ними работать. Можно создавать массивы из наших собственных типов данных. Например, string- это уже класс, просто мы пользовались им по умолчанию, но не задумывались. Или вот ещё классы: ifstream, ofstream.

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

Общая структура такова: class cat { } ;

Тут cat- это имя класса. Далее мы сможем создавать объекты типа cat, например cat x. Или даже массив: cat *x= new cat [n]; Заметим, что после объявления класса (после закрывающейся фигурной скобки) ставится точка запятой- её, пожалуйста, не нужно забывать.

В классе могут быть данные двух типов- public и privat. Данные типа паблик- к ним есть доступ со всех других участков программы. Приват- доступ есть только в пределах объявления класса. Наличие приватных данных называют также инкапсуляцией. По умолчанию все данные в классе имеют тип приват, поэтому они будут недоступны. Советую вначале делать все объекты типа паблик и не заморачиваться.

Например, создадим класс точки, т.е. тип данных "точка". Она будет состоять из 3 координат: x, y, z.

class point {

public:

// атрибуты класса

double x, y, z;

// тут далее идёт конструктор класса- его на первых порах желательно писать обязательно, хотя можно обойтись и без него

point (double x1=0, double y1=0, double z1=0) { x=x1; y=y1; z=z1; }

// тут x1=0 и т.п. это значения по умолчанию- т.е. при создании переменной типа точки у нас автоматически все координаты будут равны нулю

};

 

Ну и соответственно тип private пишется аналогично:

class cat {

private:

// что-нибудь

public:

// ещё что-нибудь

};

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

Например, создадим point.h и поместим туда класс. Естественно, нужно не забыть ifndef и прочее- я это показывал в 13-й главе, можешь вернуться туда и напомнить себе как это делается.

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

double q2 (double x) { return x*x; }

double dist (point M, point N) {

           return sqrt ( q2(M.x-N.x) + q2(M.y-N.y) + q2(M.z-N.z) );

}

M.x- это обращение к координате x для точки под названием M.

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

point M, N, P;

Или даже сразу давать начальные значения: point M(4, 3.56, -2.8), N;

Для ввода координат точки N можно сделать так: cin >> N.x >> N.y >> N.z;

И далее вывести расстояние: cout << dist(M, N) << endl;

...

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

double modradvect () {

           return sqrt(x*x+y*y+z*z);

}

Или всё объявление класса теперь будет таким:

class point {

public:

double x, y, z;

point (double x1=0, double y1=0, double z1=0) { x=x1; y=y1; z=z1; }

double modradvect () { return sqrt(x*x+y*y+z*z); }

};

Теперь, если мы создадим точку M, например: point M(5,1,0); то можно вывести модуль её радиус-вектора так: cout << M.modradvect() << endl;

Это мы уже видели, например метод c_str() для string или метод open для ifstream или ofstream. Но ты можешь сам создавать свои методы, как на примере выше.

...

Теперь создадим класс (тип данных) треугольника: он будет включать в себя 3 точки.

class tring {

public:

point A, B, C;

tring (point A1=(0,0,0), point B1=(0,0,0), point C1=(0,0,0)) {

           A= A1; B= B1; C= C1;

}

// далее будет пара методов, например координаты центра тяжести треугольника и 3 стороны

// центр тяжести

point GravityCenter() {

           point m;

           m.x= (A.x + B.x + C.x) / 3;

           m.y= (A.y + B.y + C.y) / 3;

           m.z= (A.z + B.z + C.z) / 3;

           return m;

}

// стороны треугольника

double SideA() { return dist(B,C); }

double SideB() { return dist(A,C); }

double SideC() { return dist(A,B); }

};

Теперь можно на основе предыдущих методов (стороны) дописать новый метод- площадь треугольника. Сделаем это по формуле Герона. Полупериметр занесём в приват- т.е. он будет недоступен вне класса.

class tring {

private:

double pp() { return ( SideA() + SideB() + SideC() ) / 2; }

public:

point A, B, C;

tring (point A1=(0,0,0), point B1=(0,0,0), point C1=(0,0,0)) { A= A1; B= B1; C= C1; }

point GravityCenter() {

           point m;

           m.x= (A.x + B.x + C.x) / 3;

           m.y= (A.y + B.y + C.y) / 3;

           m.z= (A.z + B.z + C.z) / 3;

           return m;

}

double SideA() { return dist(B,C); }

double SideB() { return dist(A,C); }

double SideC() { return dist(A,B); }

double Square () { return sqrt ( (pp()-SideA())*(pp()-SideB())*(pp()-SideC())*pp() ); }

};

Ну и private: можно было не писать т.к. приват ставится по умолчанию. Но так обычно более наглядно.

Теперь можно использовать то что мы создали:

point M(2,1,4), N(5,0,7), P; // создали 3 точки, у точки P нулевые координаты по умолчанию

tring a(M,N,P); // создали треугольник по 3 точкам

cout << a.Square() << endl; // вычислили площадь созданного треугольника

А вот a.pp() т.е. полупериметр мы вывести не сможем- т.к. pp() у нас занесено при объявлении класса в приват, т.е. недоступную зону. Полупериметр мы показывать не хотим, он нам понадобился лишь для вычисления площади- вот пример т.н. инкапсуляции.

Методы внутри класса могут принимать также дополнительные переменные, которые никак не связаны с классом- это уже будут аргументы. Например, умножение точки на число сделаем в самом классе:

point kPoint (double k) { point c; c.x= k*x; c.y= k*y; c.z= k.z; return c; }

Домашнее задание

Создать класс для отрезка- можно назвать его line. Отрезок у нас будет строится из 2 двумерных точек, т.е. нужно создать класс также для двумерной точки. Для класса отрезка определить метод вычисления длины отрезка. Если интересно и хорошо знаешь математику, можешь придумать и другие методы. В общем, потренируйся. И затем создай 10 отрезков в цикле из любых координат- зависящих от итераций или случайных- и вычисли их длины. Или можешь создать массив из 10 отрезков со случайными координатами и вывести номера тех отрезков, у которых длина превышает единицу. Вот тебе примерочные задания для тренировки и закрепления темы. Попробуй сделать это сам, проверки тут не будет. Делай на основе того что я писал выше- класс трёхмерной точки и класс треугольника. Информации, изложенной в данной главе, достаточно чтобы сделать то что тебе тут просится.

* Длина отрезка вычисляется как расстояние между 2 точками- началом и концом отрезка.

 


Дата добавления: 2018-09-22; просмотров: 165; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!