Тема:
«Понятие абстракции. Классы в С++»
План
3. Конструктор и деструктор класса
Но естественно, повар не готовит каждую пиццу с нуля в том порядке, как здесь описано. Это заняло бы годы. Вместо этого он готовит всё заранее, а когда очередь доходит до Неаполитаны, всё что ему нужно, это взять основу (которая уже сформирована), добавить томатный соус, анчоусы и сыр, и затем запечь в духовке.
Важная вещь, которую здесь нужно понять, это то, что что повару надо знать лишь ингредиенты для каждой конкретной пиццы, а в остальном все пиццы похожи одна на другую. Программирование выглядит очень похоже, вы используете «абстракции» для хранения более общих данных (это как основа пиццы), отделяя их от более специфичных (начинка).
Перейдем от приготовления пиццы в написание кода. Сначала начнём делать это неправильно. Сделаем метод make_a_napoletana_pizza (приготовить пиццу Неаполитана):
make_a_napoletana_pizza
В нём будет 5 шагов (сделать основу, добавить томатный соус, добавить анчоусы, добавить сыр, запечь):
make_the_base
add_the_tomato_sauce
add_anchovy
add_cheese
bake
Но что, если мы хотим сделать пиццу салями? Мы будем вынуждены написать абсолютно новый метод make_a_salami_pizza (приготовить пиццу салями), у которого будет много общего с текущим методом, разве что он будет добавлять салями вместо анчоусов. Это несколько затратно. Программистский подход состоит в том, чтобы «абстрагировать» общие части методов приготовления пиццы и учесть различающиеся, специфичные ингредиенты. Мы можем сделать это с помощью «аргумента», который «передаётся» в метод.
Вот что имеется ввиду. Представим, что наш метод make_a_pizza (приготовить пиццу) вызывается с аргументом «toppings» (начинки). Метод будет выглядеть примерно так:
make_a_pizza(toppings)
И он будет работать следующим образом:
make_the_base
add_the_tomato_sauce
add_toppings(toppings)
add_cheese
bake
В 3-й строке мы берём начинки, определённые ранее, и добавляем их в пиццу.
Теперь, когда мы определили общий метод по приготовлению пиццы, мы можем просто вызвать его и задать ингредиенты, которые хотим. Всё происходит автоматически. Другими словами, мы вызываем make_pizza(salami), и когда метод запустится, salami (салями) станет toppings (начинкой) и добавится в пиццу, когда метод дойдёт до 3-й строки. Просто изменяя начинку, можно одним методом создать 2 разные пиццы. Это так же экономно, как когда официантка просто пишет в форме заказа «1 х салями, 1 х вегетарианская», и повар знает всё, что ему нужно. В программировании это называется «абстракция». (начало)
Классы и объекты в
С++ являются основными концепциями объектно-ориентированного
программирования – ООП.
Чтобы понять, для чего же нужны
классы, проведём аналогию с каким-нибудь объектом из повседневной жизни,
например, с велосипедом. Велосипед – это объект, который был построен согласно
чертежам. Эти чертежи играют роль классов в ООП. Таким образом, классы – это некоторые описания, схемы,
чертежи по которым создаются объекты.
Для создания объекта в ООП необходимо сначала составить чертежи, то есть
классы. Классы имеют свои функции, которые называются методами класса. Передвижение велосипеда осуществляется за счёт
вращения педалей, если рассматривать велосипед с точки зрения ООП, то механизм
вращения педалей – это метод класса. Каждый велосипед имеет свой цвет, вес,
различные составляющие – всё это свойства.
Причём у каждого созданного объекта свойства могут различаться. Имея один
класс, можно создать неограниченное количество объектов (велосипедов), каждый
из которых будет обладать одинаковым набором методов, при этом можно не
задумываться о внутренней реализации механизма вращения педалей, колёс,
срабатывания системы торможения, так как всё это уже будет определено в классе.
Разобравшись с назначением класса, дадим ему грамотное определение.
Классы в С++ – это абстракция описывающая методы, свойства, ещё не
существующих объектов. Объекты – конкретное представление
абстракции, имеющее свои свойства и методы. Созданные объекты на основе одного
класса называются экземплярами этого
класса. Эти объекты могут иметь различное поведение, свойства, но все равно
будут являться объектами одного класса. В ООП существует три основных принципа
построения классов:
Рассмотрим структуру объявления
классов.
// объявление классов в С++
class /*имя
класса*/
{
private:
/* список свойств и
методов для использования внутри класса */
public:
/* список методов,
доступных другим функциям и объектам программы */
protected:
/*список средств,
доступных при наследовании*/
};
Объявление
класса начинается с зарезервированного ключевого слова class,
после которого пишется имя класса. В фигурных скобках
объявляется тело класса, причём после закрывающейся скобки обязательно нужно
ставить точку с запятой. В теле класса объявляются три метки спецификации
доступа private, public, protected.
После каждой метки нужно обязательно ставить двоеточие.
Все
методы и свойства класса, объявленные после спецификатора
доступа private
будут доступны только внутри класса.
Все
методы и свойства класса, объявленные после спецификатора
доступа public
будут доступны другим функциям и объектам в программе.
При
объявлении класса, не обязательно объявлять три спецификатора доступа, и не
обязательно их объявлять в таком порядке.
Модификатор
доступа в классе по умолчанию private,
поэтому слово private:
писать не обязательно.
Ниже
приведены две равнозначные записи:
class summa
{
private: int x,y,z;
public:
int a;
};
class summa
{
int x,y,z;
public: int a;
};
Пример.
Составим программу, с описанием класса, в котором будет объявлена функция,
печатающая сообщение.
#include <iostream.h>
// начало объявления класса
class printer // printer – имя класса
{
public: // спецификатор доступа
void message() //функция,
выводящая текстовое сообщение на экран
{
cout<<"Hello!"<<endl;
}
}; // конец объявления класса printer
int main()
{
printer mes; // объявление объекта
mes.message(); // вызов функции класса printer
system("pause");
return 0;
}
В
примере определен класс с именем printer.
В теле класса объявлен спецификатор доступа public,
который позволяет вызывать другим функциям методы класса, объявленные после public. Именно поэтому в
главной функции, можно вызвать функцию message().
В классе printer
объявлена одна функция, которая не имеет параметров и выводит сообщение на
экран. Методы класса – это те же функции, только объявленные внутри класса.
Объявление классов выполняется аналогично объявлению функций, то есть класс
можно объявлять в отдельном файле или в главном файле.
В
функции main()
объявлена переменная mes
типа printer.
Переменная mes
– это объект класса printer.
После того как объект класса объявлен, можно использовать его методы. Метод
всего один – функция message().
Обращаются к методу объекта printer
через точку, в результате программа выдаст текстовое сообщение.
Для данного
примера можно использовать другую форму описания функций внутри класса:
#include <iostream.h>
class printer
{
public:
void message(); // описание функции
};
// реализация функции
void printer::message()
{
cout<<"Hello!"<<endl;
}
int main()
{
printer mes; // объявление объекта
mes.message(); // вызов функции класса printer
system("pause");
return 0;
}
Пример.
Сложить два числа, используя классы.
#include <iostream.h>
//объявляем класс summa
class summa
{
private:
int x,y;
public:
//Функция доступна из любого места программы
//Вводим через функцию 2 числа
void vvod()
{
cout<<"Vvedite x, y"<<endl;
cin>>x>>y;
}
int raschet() //Функция суммирования двух чисел
{
return x+y; //х,у
берутся из класса
}
};
int main()
{
summa obj; //объект класса summa
//обращаемся к объекту класса и через него вызываем функцию ввода
данных
obj.vvod();
//обращаемся к объекту класса
//и через него вызываем функцию нахождения суммы чисел х
и у
cout<<"Summa="<<obj.raschet()<<endl;
system("pause");
return 0;
} (начало)
Конструктор
– это специальная функция, которая выполняет начальную инициализацию данных.
Имя конструктора обязательно должно совпадать с именем класса. Конструктор не
возвращает никаких значений, в том числе и void.
Вызов конструктора происходит автоматически, сразу после создания объекта этого
класса.
Деструктор
– также специальная функция, которая вызывается при уничтожении объекта. Имя
деструктора обязательно должно совпадать с именем класса, только в начале ставится знак тильды ~. Деструктор не имеет входных
параметров.
Пример.
Создать динамический одномерный массив c помощью
таких методов класса:
- конструктор (создает массив из 10 элементов и заполняет
их -1);
- метод выделения памяти под динамический массив;
- метод формирования массива на отрезке;
- метод вывода массива на экран.
Описать класс и реализацию всех его методов.
#include <iostream.h>
#include <ctime>
//описание класса
class massiv
{
public:
//описание переменных
float *mas; //описание
динамического массива
int n; //размер
массива
//описание методов
void create(); //метод
выделения памяти под динамический массив
void fill(); //метод
формирования массива на отрезке
void show(); //метод вывода
массива
void del(); //метод
освобождения памяти от массива
massiv(); //конструктор
};
//реализация конструктора
massiv::massiv()
{
int i;
//задаем размер массива в 10
элементов,
n=10;
//выделяем память под 10
элементов массива
mas=new float[n];
//все элементы массива
заполняем -1
for (i=0; i<=9; i++)
mas[i]=-1;
}
//реализация метода выделения памяти под динамический массив
void massiv::create()
{
cout<<"Введите размер
массива";
cin>>n;
//выделяем память под n элементов массива
mas=new float[n];
}
//реализация метода формирования массива на отрезке
void massiv::fill()
{
int i;
srand(time(0));
float a,b;
cout<<"Введите
диапазон заполнения массива ";
cin>>a>>b;
for (i=0; i<=n-1; i++)
mas[i]=(b-a)*rand()/32676+a;
}
//реализация метода вывода массива на экран
void massiv::show()
{
int i;
for (i=0; i<=n-1; i++)
cout<<mas[i]<<"
";
}
//реализация метода освобождения памяти от массива
void massiv::del()
{
delete[] mas;
}
int main()
{
//описание объекта типа massiv
massiv m1;
cout<<"Массив, созданный
конструктором:"<<endl;
//вывод элементов массива,
заполненных конструктором
m1.show();
cout<<"Создаем
массив:"<<endl;
//вызов методов
m1.create(); //вызов метода выделения памяти под динамический массив
m1.fill(); //вызов метода формирования массива на отрезке
m1.show(); //вызов метода вывода массива
m1.del(); //вызов метода освобождения памяти от массива
system("pause");
return 0;
} (начало)