ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
Классы
Сначала программирование было только процедурным. Но затем, чем больше и крупнее становились проекты, программы, тем больше появилась необходимость в изобретении такой вещи как классы и объектно-ориентированного программирования в целом.
Сначала ты можешь не понимать- зачем это всё нужно, ведь и так с функциями, шаблонами, массивами и заголовочными файлами всё нормально. Но позже, чем больше ты будешь программировать, чем более сложными и громоздкими будут становиться твои проекты, тем больше ты будешь приходить к необходимости введения классов. Классы позволяют ещё больше обобщать и упрощать код. Вместо изменения сотен строк во всей программе мы можем менять просто пару строк в классе и всё будет так же замечательно работать.
Класс- это свой собственный тип данных. Мы уже знаем примитивные встроенные типы данных- 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; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!