Деструктор
Деструктор в рассматриваемом классе можно не реализовывать. Это обусловлено тем обстоятельством, что отсутствуют операции, которые он должен выполнять.
Приведем теперь окончательную реализацию разработанного класса B_1.
//Файл B_1.cpp B_1 :: B_1() : m_(0) { }
B_1 :: B_1(const A& a, int m) : a_(a), m_(m) { }
B_1 :: B_1(const B& rhs) : a_(rhs.a_), m_(rhs.m_) { }
void B_1 :: display() { a_.disply(); cout << “m = ” << m_ << endl; }
Отметим, что класс A оказывается включенным в класс B1 в соответствии с принципом композиции. Приведем законченную диаграмму классов для рассматриваемого примера.

Разработка класса B_2.
Напишем для него заголовочный файл. Обратите внимание на то, что добавлен деструктор.
// Файл B_2.h
class B_2
{
public:
B_2();
B_2(const A& a, int m);
B_2(const B_2_1& rhs); ~B_2(); void display();
private:
A *pa_;
int m_;
};
Перейдем к разработке реализации класса B_2. Отметим ряд важных исходных положений для реализации. При работе с указателями одним из центральных вопросов является вопрос о том, кто «владеет» объектом, на который установлен указатель (указатель pa_). Решение упрощается, если полагать, что права «владения» находятся у агрегатного объекта (объекта класса B_2). Будем предполагать, что в любом своем состоянии объект агрегатного класса содержит объект класса A.
Реализация класса b_2.
// Файл B2.cpp B_2 :: B_2() : pa_(new A), m_(0) { } B_2 :: B_2(const A& a, int m) : pa_(new A(a)), m_(m) { }
B_2 :: B_2(const B_2_1& rhs) : pa_(new A(*rhs.pa_)), m_(rhs.m_) { } B_2 :: ~B_2() { delete pa_; } void B_2 :: display() { pa_->display(); cout << “m = ” << m << endl; }
Обсуждение. В этой реализации класс целое (B_2) «владеет» объектом, на который установлен его указатель pa_. После уничтожения объекта этого класса будет уничтожен и объект его компонента класса A. Можно считать, что классы A и B_2 связаны отношением композиции.
Пример организации классов для лабораторной работы
|
Класс №1 |
Свойства (Класс №1) |
Класс №2 |
Свойства (Класс №2) |
|
CSpine (Позвоночник) |
Float LeightSpine (Длинна позвоночника, например – 17) String NameSpine (Название позвонка, например - Шейный) |
CMammal (Млекопитающее) |
Float WeightMammal (Вес млекопитающего, например – 25) CSpine* MammaFeatures |
Дополнение.
Возможны следующие варианты организации классов:
а) организуется модули отдельно для класса CSpine и CMammal;
б) организуется общий модуль для указанных классов.
Вариант а) является предпочтительным.
Пример на основе двух классов: Spine и Mammal:
#include "pch.h"
#include <iostream>
#include <string>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
/*Создаем класс Spine(Позвоночник)*/
class Spine
{
/*Объявляем переменную lengthSpine(Длина позвоночника) типа float и
переменную WallColor(Название позвоночника) типа string c модификатором доступа private */
private:
float lengthSpine;
string nameSpine;
public:
/*Объявляем конструктор по умолчанию*/
Spine()
{
/*Производим отладочную печать работы конструктора по умолчанию и инициализируем переменные lengthSpine и nameSpine */
cout << "Конструктор по умолчанию Spine" << endl;
lengthSpine = 0.6;
nameSpine = "Грудной";
}
/*Объявляем конструктор, который принимает в качестве параметров две переменные:
lengthSpine типа float и nameSpine типа string.
В инициализации конструктора инициализируем переменные lengthSpine и nameSpine полученными значениями */
Spine(float lengthSpine, string nameSpine) : lengthSpine(lengthSpine), nameSpine(nameSpine)
{
/*Производим отладочную печать работы конструктора с параметром*/
cout << "Конструктор c параметрами Spine" << endl;
}
/*Объявляем конструктор копирования Spine, который принимает в качестве параметра объект Spine с именем cpySpine
В инициалиации конструктора копируем поля объекта cpySpine в lengthSpine и nameSpine соответственно скопированным значениями*/
Spine(const Spine& cpySpine) : lengthSpine(cpySpine.lengthSpine), nameSpine(cpySpine.nameSpine)
{
/*Производим отладочную печать работы конструктора копирования*/
cout << "Конструктор копирования Spine" << endl;
}
/*Объявляем перегруженный оператор присваивания*/
Spine& operator=(const Spine &spine)
{
/*Производим отладочную печать работы перегруженного оператора присваивания
Копируем поля объекта cpySpine в lengthSpine и nameSpine соответственно*/
cout << "Перегруженный оператор присваивания Spine" << endl;
this->lengthSpine = spine.lengthSpine;
this->nameSpine = spine.nameSpine;
/*Возвращаем текущий объект*/
return *this;
}
/*Объявляем деструктор*/
~Spine()
{
/*Производим отладочную печать работы деструктора*/
cout << "Деструктор Spine" << endl;
}
/*Объявляем setter для записи значения в private lengthSpine*/
void setLengthSpine(float lengthSpine)
{
this->lengthSpine = lengthSpine;
}
/*Объявляем getter для получения значения из private lengthSpine*/
float getLengthSpine()
{
return lengthSpine;
}
/*Объявляем setter для записи значения в private nameSpine*/
void setNameSpine(string nameSpine)
{
this->nameSpine = nameSpine;
}
/*Объявляем getter для получения значения из private nameSpine*/
string getNameSpine()
{
return nameSpine;
}
/*Метод вывода print полей класса*/
void print()
{
cout << "Длина позвоночника: " << lengthSpine << " м." << endl;
cout << "Название позвоночника: " << nameSpine << endl;;
}
};
/*Создаем класс Mammal(Млекопитающее)*/
class Mammal
{
/*Объявляем переменную weightMammal(Вес млекопитающего) типа float
и объявляем указатель mammalFeatures(Особенности млекопитающего) на класс Spine c модификатором доступа private */
private:
float weightMammal;
Spine* mammalFeatures;
public:
/*Объявляем конструктор по умолчанию*/
Mammal()
{
/*Производим отладочную печать работы конструктора по умолчанию и инициализируем переменную weightMammal значением,
и выделяем память для mammalFeatures */
cout << "Конструктор по умолчанию Mammal" << endl;
weightMammal = 25.5;
mammalFeatures = new Spine[2];
}
/*Объявляем конструктор, который принимает в качестве параметров три переменные:
lengthSpine типа float, nameSpine типа string и weightMammal типа float.
В инициализации конструктора инициализируем переменную weightMammal полученным значением */
Mammal(float lengthSpine, string nameSpine, float weightMammal) : weightMammal(weightMammal)
{
/*Производим отладочную печать работы конструктора с параметрами, выделяем память для mammalFeatures,
передавая в качестве размерности 2 и вызываем setter`ы setLengthSpine и setNameSpine класса Spine,
передавая в качестве параметров переменные lengthSpine и nameSpine соответственно */
cout << "Конструктор с параметром Mammal " << endl;
mammalFeatures = new Spine[1];
mammalFeatures->setLengthSpine(lengthSpine);
mammalFeatures->setNameSpine(nameSpine);
}
/*Объявляем конструктор копирования Mammal, который принимает в качестве параметров объект Mammal
с именем cpyMammal.
В инициализации конструктора инициализируем переменную weightMammal скопированным значением */
Mammal(const Mammal& cpyMammal) : weightMammal(cpyMammal.weightMammal)
{
/*Производим отладочную печать работы конструктора копирования. Выделяем память для mammalFeatures, передавая в качестве размерности 1
Копируем поля объекта cpyMammal в mammalFeatures соответственно*/
cout << "Конструктор копирования Mammal" << endl;
this->mammalFeatures = new Spine[1];
this->mammalFeatures[0] = cpyMammal.mammalFeatures[0];
}
/*Объявляем перегруженный оператор присваивания*/
Mammal& operator=(const Mammal &mammal)
{
/*Производим отладочную печать работы перегруженного оператора присваивания*/
cout << "Перегруженный оператор присваивания Mammal" << endl;
/*Проверка на выделенность памяти. Если выделено-очищаем*/
if (this->mammalFeatures != nullptr)
{
delete[] this->mammalFeatures;
}
/*Выделяем память*/
this->mammalFeatures = new Spine[1];
/*Копируем поля объекта mammal в weightMammal и в цикле mammalFeatures соответственно*/
weightMammal = mammal.weightMammal;
this->mammalFeatures[0] = mammal.mammalFeatures[0];
/*Возвращаем текущий объект*/
return *this;
}
/*Объявляем деструктор*/
~Mammal()
{
/*Производим отладочную печать работы деструктора и освобождаем выделенную память для mammalFeatures*/
cout << "Деструктор Mammal" << endl;
delete[] mammalFeatures;
}
/*Объявляем setter для записи значения в private weightMammal*/
void setWeightMammal(float weightMammal)
{
this->weightMammal = weightMammal;
}
/*Объявляем getter для получения значения из private weightMammal*/
float getWeightMammal()
{
return weightMammal;
}
/*Метод вывода print полей класса*/
void print()
{
/*Вызываем метод print из класса Spine*/
mammalFeatures->print();
cout << "Вес млекопитающего: " << weightMammal << " кг." << endl;
}
};
int main()
{
/*Объявляем переменные lengthSpine и weightMammal типа float и nameSpine типа string*/
float lengthSpine, weightMammal;
string nameSpine;
/*Устанавливаем русский язык*/
system("chcp 1251");
/*Очищаем окно консоли*/
system("cls");
cout << "Введите название позвоночника: ";
/*Считываем переменную nameSpine, введенной с клавиатуры*/
cin >> nameSpine;
cout << "Введите длину позвоночника: ";
/*Считываем переменную lengthSpine, введенной с клавиатуры*/
cin >> lengthSpine;
cout << "Введите вес млекопитающего: ";
/*Считываем переменную weightMammal, введенной с клавиатуры*/
cin >> weightMammal;
cout << "----------------------------------------------------------------------------" << "\n"
<< "----------------------------------------------------------------------------" << endl;
/*Объявляем экземпляр класса Mammal с именем defaultMammal, который вызывает конструктор по умолчанию*/
Mammal defaultMammal;
/*Выводим на экран получившиеся данные*/
defaultMammal.print();
cout << "----------------------------------------------------------------------------" << "\n"
<< "----------------------------------------------------------------------------" << endl;
/*Объявляем экземпляр класса Mammal с именем mammalWithUserConstr, который вызывает конструктор с параметрами*/
Mammal mammalWithUserConstr(lengthSpine, nameSpine, weightMammal);
/*Выводим на экран получившиеся данные*/
mammalWithUserConstr.print();
cout << "----------------------------------------------------------------------------" << "\n"
<< "----------------------------------------------------------------------------" << endl;
/*Объявляем экземпляр класса Mammal с именем cpyMammal, который вызывает конструктор копирования*/
Mammal cpyMammal(mammalWithUserConstr);
/*Выводим на экран получившиеся данные*/
cpyMammal.print();
cout << "----------------------------------------------------------------------------" << "\n"
<< "----------------------------------------------------------------------------" << endl;
/*Объявляем экземпляр класса Mammal с именем overloadedMammal, который вызывает конструктор по умолчанию*/
Mammal overloadedMammal;
/* Инициализируем экземпляр класса overloadedMammal экземпляром класса mammalWithUserConstr,
в результате этого вызывается перегруженный оператор присваивания */
overloadedMammal = mammalWithUserConstr;
/*Выводим на экран получившиеся данные*/
overloadedMammal.print();
cout << "----------------------------------------------------------------------------" << "\n"
<< "----------------------------------------------------------------------------" << endl;
/*Объявляем экземпляр класса Spine с именем defaultSpine, который вызовет конструктор по умолчанию*/
Spine defaultSpine;
/*Выводим на экран получившиеся данные*/
defaultSpine.print();
cout << "----------------------------------------------------------------------------" << "\n"
<< "----------------------------------------------------------------------------" << endl;
/*Объявляем экземпляр класса Spine с именем spineWithUserConstr, который вызовет конструктор с параметрами*/
Spine spineWithUserConstr(lengthSpine, nameSpine);
/*Выводим на экран получившиеся данные*/
spineWithUserConstr.print();
cout << "----------------------------------------------------------------------------" << "\n"
<< "----------------------------------------------------------------------------" << endl;
/*Объявляем экземпляр класса Spine с именем spineWithUserConstr, который вызовет конструктор копирования*/
Spine cpySpine(spineWithUserConstr);
/*Выводим на экран получившиеся данные*/
cpySpine.print();
cout << "----------------------------------------------------------------------------" << "\n"
<< "----------------------------------------------------------------------------" << endl;
/*Объявляем экземпляр класса Mammal с именем overloadedSpine, который вызывает конструктор с параметрами*/
Spine overloadedSpine(lengthSpine, nameSpine);
/* Инициализируем экземпляр класса overloadedSpine экземпляром класса defaultSpine,
в результате этого вызывается перегруженный оператор присваивания */
overloadedSpine = defaultSpine;
/*Выводим на экран получившиеся данные*/
overloadedSpine.print();
cout << "----------------------------------------------------------------------------" << "\n"
<< "----------------------------------------------------------------------------" << endl;
}
