что такое конструкторы и деструкторы с

Конструкторы и деструкторы

Конструкторы

Конструктор — функция, предназначенная для инициализации объектов класса. Рассмотрим класс date :

Если конструктор требует аргументы, их следует указать:

Если необходимо обеспечить несколько способов инициализации объектов класса, задается несколько конструкторов:

Конструкторы подчиняются тем же правилам относительно типов параметров, что и перегруженные функции. Если конструкторы существенно различаются по типам своих параметров, то компилятор при каждом использовании может выбрать правильный:

Одним из способов сократить количество перегруженных функций (в том числе и конструкторов) является использование значений по умолчанию.

Конструктор по умолчанию

При создании объекта вызывается конструктор, за исключением случая, когда объект создается как копия другого объекта этого же класса, например:

Однако имеются случаи, в которых создание объекта без вызова конструктора осуществляется неявно:

Во всех этих случаях транслятор не вызывает конструктора для вновь создаваемого объекта:

Вместо этого в них копируется содержимое объекта-источника:

Конструктор копии

Как правило, при создании нового объекта на базе уже существующего происходит поверхностное копирование, то есть копируются те данные, которые содержит объект-источник. При этом если в объекте-источнике имеются указатели на динамические переменные и массивы, или ссылки, то создание копии объекта требует обязательного дублирования этих объектов во вновь создаваемом объекте. С этой целью вводится конструктор копии, который автоматически вызывается во всех перечисленных случаях. Он имеет единственный параметр — ссылку на объект-источник:

Деструкторы

Определяемый пользователем класс имеет конструктор, который обеспечивает надлежащую инициализацию. Для многих типов также требуется обратное действие. Деструктор обеспечивает соответствующую очистку объектов указанного типа. Имя деструктора представляет собой имя класса с предшествующим ему знаком «тильда»

. Так, для класса X деструктор будет иметь имя

Поля, имеющие тип класса

Конструкторы членов класса всегда выполняются до конструктора класса, в котором эти члены описаны. Порядок выполнения конструкторов для членов класса определяется порядком объявления членов класса. Если конструктору члена класса требуются аргументы, этот член с нужными аргументами указывается в списке инициализации. Деструкторы вызываются в обратном порядке.

Источник

Что такое конструкторы и деструкторы с

Любой переменной, участвующей в работе программы, требуется память и некоторое начальное значение. Для переменных встроенных типов размещение в памяти обеспечивается компилятором. Для локальных переменных память выделяется из стека программы и занимается для хранения значения данной переменной до тех, пока не закончится время ее жизни. Сложные типы данных также должны размещаться в памяти и уничтожаться когда их время жизни закончилось. Это осуществляется с использованием конструкторов и деструкторов.

имя класса, предназначенная для уничтожения переменных (delete).

Одной из особенностей конструктора и деструктора является то, что в отличие от всех остальных функций, у них нет возвращаемого значения.

4.3.1. Конструкторы

Конструктор по умолчанию

Конструктор, не требующий аргументов, называется конструктором по умолчанию. Конструктор по умолчанию не имеет аргументов и инициализирует все переменные члены какими-либо начальными значениями.

При создании любого экземпляра класса вызывается конструктор. Если при описании экземпляра не указываются никакие параметры – вызывается конструктор по умолчанию:

Полный конструктор

Полный конструктор позволяет явно инициализировать все переменные-члены класса.

Если при описании экземпляра класса в скобках указать параметры, при создании экземпляра класса будет вызван полный конструктор и переменные-члены инициализируются указанными значениями.

Неполный конструктор

Возможен и неполный конструктор, когда в списке параметров указываются не все возможные параметры для инициализации членов класса, а только наиболее часто используемые. Остальные параметры будут инициализированы значениями по умолчанию.

Инициализация переменных-членов класса в конструкторах может осуществляться не только в теле конструктора, но и после оператора :. При этом, во время присваивания переменной-члену значения, будет вызываться не оператор присваивания, а конструктор. Для встроенных типов данных, таких как double или int, это не существенно, но если членами класса являются абстрактные типы, вызов конструктора вместо оператора присваивания будет выполняться быстрее.

Конструктор копирования

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

4.3.2. Деструктор (пример 4.4. Конструктор и деструктор класса Матрица)

Деструктор осуществляет освобождение памяти, например уничтожение объектов размещенных динамически.

В классе Lens никакого динамического размещения не происходило, поэтому деструктор будет пустой, но его наличие все равно обязательно. Для примера реализации деструктора, представим, что имеется класс Matrix, который в конструкторе динамически создает двумерный массив размерности n x m. Тогда деструктор должен освобождать память, которую выделяет конструктор.

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

4.3.3. Проверка правильности параметров. Исключительные ситуации

Конструкторы должны проверять передаваемые им аргументы на корректность значений. Например, показатель преломления не может быть меньше 1. Что делать, если в конструктор были переданы неправильные параметры? Для этого в языке С++ существуют исключительные ситуации.

Класс exception является стандартным базовым классом C++ для всех исключений. Исключения можно сгенерировать в случае возникновения непредвиденной ошибки, например мы предполагаем что при вызове класса Lens никто не будет пытаться задать показатель преломления меньше 1, но при этом такая ситуация возможна, и это может привести к ошибке. Сгенерировать исключительную ситуацию можно при помощи оператора throw:

Для обработки возникшей исключительной ситуации используются try и catch блоки.

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

Если при выполнение какого-то оператора из блока try возникает исключение – управление сразу переходит к блоку catch. В блоке catch в скобках указывается тип исключения (exception это наиболее общий вид исключения, возможны и другие типы) и имя исключения. Внутри блока catch необходимо обработать ошибку. В нашем случае мы просто выводим на экран сообщение, в каких-то случаях потребуется более сложная обработка. Функция what() содержит текст, сгенерированный в момент создания исключения.

В результаты выполнения данного блока программы на экран выведется сообщение » Index of refraction should be greater than 1.».

Если никаких исключений в try-блоке не происходит, программа игнорирует его catch-обработчик.

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

Источник

Объектно ориентированное программирование на Си без плюсов. Часть 1. Введение

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

Статья рассчитана на тех кто уже знаком с Си, а все примеры ориентированы на ОС Linux. Мои познания Windows закончились на «WinXP», после которой в Windows стало уже очень много политики («безопасности») и коммерческой составляющей, но я сейчас не об этом и надеюсь, что здесь вы найдёте для себя полезные моменты, а если я в чём-то не прав или заблуждаюсь, то поправите.

Так сложилось, что изучать традиции ООП я начал с Delphi и Java, являющихся, как считается, на 100% объектно ориентированными языками программирования, а потому аналогия решений у меня ассоциируется именно с ними. И далее в тексте я иногда буду на них ссылаться, что надеюсь не испортит суть полного понимания.

В соответствии с определениями ООП все сущности должны быть объектами обладающими некоторыми свойствами и принадлежать к определённому классу.

У классов должны быть:

Конструктор и деструктор для рождения и уничтожения объектов соответственно;

Методы информирующие о изменении состояния (события);

Методы определяющие поведение объектов.

Для написания классов я предлагаю постепенно в тексте вводить простые правила нотации:

Новый файл — новый класс, как в Java. Вернее заголовочный файл mynewclass.h + основной файл mynewclass.c;

Перед именем функции пишется имя класса, например: void myclass_namefunction(…);

Перед новым определяемым типом пишется « t_ », например: t_mynewtype;

В макросах все вновь вводимые переменные начинаются с двойного подчёркивания, например: __i;

1. Начну с конструктора и деструктора.

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

У деструктора обратная задача — навести порядок и высвободить задействованные вычислительные ресурсы.

В соответствии с принятой нотацией типовой конструктор это функция, которая может выглядеть, как-то так:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Ну, а деструктор соответственно:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Реализацию событий можно организовать при помощи указателей на функции. Я посчитал, что включать указатели на функции в общую структуру объекта нет смысла, да и расточительно выделять дополнительную память каждый раз при создании объекта. И, указатели на функции обратных вызовов (событий) решил объединять в отдельную структуру, имя которой содержит имя класса, а имена функций начинаются с «on_» например:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Таким образом, помещая объявленную структуру в заголовочный файл получаем аналогию интерфейса, как в Java, который можно использовать например так:

В структуру нашего нового класса добавляем указатель на тип t_mynewclass_events, т.е.:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

В файлах классах реализуем функцию «сеттер»:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

В основном файле программы, используем всё это как-то так:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Ну, а в функциях класса вызываем событие так:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Собственно вот и вся реализация так называемого callback-а.

В части методов, определяющих поведение объекта и доступных из вне (т.е. публичных), я ещё раз повторюсь и обобщу принятое мной правило, это не включать в структуру объекта ссылки на функции (методы класса), а, просто, название функций начинать с имени класса, например: void myclass_namefunction(…);. Считаю, такое решение вполне рациональным. Принадлежность к классу всегда можно определить по имени функции, а единственное неудобство «много букв» простить.

Двигаемся далее. В основе ООП есть три основополагающих понятия: инкапсуляция, полиморфизм и наследование.

Смысл её в том, что бы разделить частное (protected, private … ) и общедоступное ( public, published … ). Частное это внутренняя «кухня» определённого класса доступ до которой ограничен.

Решение на Си простое:

В заголовочном файле mynewclass.h пишем:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Саму структуру определяем в файле mynewclass.с:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Для доступа к полям структуры в заголовочном файле прописываем прототипы публичных функций:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Реализация функций в файле mynewclass.с буде выглядеть как-то так:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Теперь доступ к переменным структуры определяется «сетерами» и «гетерами», как в Java, а в структуре struct mynewclass могут быть приватные поля и методы объекта. Здесь стоит наверное отметить следующее, в одном процессе все методы (функции) для одного нашего «Класса» являются общими. А чтобы понимать с каким объектом должна отработать функция, то первым параметром отправляем ссылку на объект её вызывающего.

С инкапсуляцией надеюсь разобрались.

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

Передача параметра в функцию через указатель void*, например так:

В начале для красоты введём собственные наименования типов при помощи перечисления:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Тогда функцию оформляем следующим образом, например:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Вызов функции будет соответственно:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Надеюсь идея ясна и понятна.

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

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

3. А можно в функцию передать любую другую функцию, например так:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Это вроде аналогичной функции Synchronize(@function) из Delphi, но сейчас не об этом.

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

А потом даже можно написать:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Компилятор такую запись должен понять, но это всё равно не похоже на наследование свойств и методов от какого-то родительского класса, а скорее наоборот — порождение потомков с определёнными свойствами и методами принадлежащими новому «родителю семейства».

Но вот, что бы потомки знали, в случае обработки события, к какому экземпляру родителя оно относится, я предлагаю у потомков прописывать «фамилию родителя», то есть добавить в структуру каждого класса переменную указатель: void* parent и пару функций для работы с ней:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

И, когда потомок вызовет указанную ему функцию-обработчик, мы сможем однозначно знать к какому экземпляру родителя это событие относится.

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

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

Хотя почему реализация не классическая? В Delphi при объявлении нового класса это обычная практика включать в класс поля переменных других классов.

В общем, разобрав реализацию основных понятий ООП для создания класса получился некий шаблон, где заголовочный файл myclass.h должен выглядеть как-то так:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Соответственно файл myclass.с должен выглядеть как-то так:

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Теоретически, представленного выше, для создания объектов должно быть достаточно, а вот для практического применения и написания подавляющего большинства программ необходимо решение в виде таймера, но об этом я хочу рассказать в следующей части.

Источник

Наследование в C++: beginner, intermediate, advanced

В этой статье наследование описано на трех уровнях: beginner, intermediate и advanced. Expert нет. И ни слова про SOLID. Честно.

Beginner

Что такое наследование?

Наследование является одним из основополагающих принципов ООП. В соответствии с ним, класс может использовать переменные и методы другого класса как свои собственные.

Класс, который наследует данные, называется подклассом (subclass), производным классом (derived class) или дочерним классом (child). Класс, от которого наследуются данные или методы, называется суперклассом (super class), базовым классом (base class) или родительским классом (parent). Термины “родительский” и “дочерний” чрезвычайно полезны для понимания наследования. Как ребенок получает характеристики своих родителей, производный класс получает методы и переменные базового класса.

Наследование полезно, поскольку оно позволяет структурировать и повторно использовать код, что, в свою очередь, может значительно ускорить процесс разработки. Несмотря на это, наследование следует использовать с осторожностью, поскольку большинство изменений в суперклассе затронут все подклассы, что может привести к непредвиденным последствиям.

Важное примечание: приватные переменные и методы не могут быть унаследованы.

Типы наследования

В C ++ есть несколько типов наследования:

Конструкторы и деструкторы

В C ++ конструкторы и деструкторы не наследуются. Однако они вызываются, когда дочерний класс инициализирует свой объект. Конструкторы вызываются один за другим иерархически, начиная с базового класса и заканчивая последним производным классом. Деструкторы вызываются в обратном порядке.

Важное примечание: в этой статье не освещены виртуальные десктрукторы. Дополнительный материал на эту тему можно найти к примеру в этой статье на хабре.

Множественное наследование

Множественное наследование происходит, когда подкласс имеет два или более суперкласса. В этом примере, класс Laptop наследует и Monitor и Computer одновременно.

Проблематика множественного наследования

Множественное наследование требует тщательного проектирования, так как может привести к непредвиденным последствиям. Большинство таких последствий вызваны неоднозначностью в наследовании. В данном примере Laptop наследует метод turn_on() от обоих родителей и неясно какой метод должен быть вызван.

Несмотря на то, что приватные данные не наследуются, разрешить неоднозначное наследование изменением уровня доступа к данным на приватный невозможно. При компиляции, сначала происходит поиск метода или переменной, а уже после — проверка уровня доступа к ним.

Intermediate

Проблема ромба

что такое конструкторы и деструкторы с. Смотреть фото что такое конструкторы и деструкторы с. Смотреть картинку что такое конструкторы и деструкторы с. Картинка про что такое конструкторы и деструкторы с. Фото что такое конструкторы и деструкторы с

Ромбовидная проблема — прежде всего проблема дизайна, и она должна быть предусмотрена на этапе проектирования. На этапе разработки ее можно разрешить следующим образом:

Проблема ромба: Конструкторы и деструкторы

Поскольку в С++ при инициализации объекта дочернего класса вызываются конструкторы всех родительских классов, возникает и другая проблема: конструктор базового класса Device будет вызван дважды.

Виртуальное наследование

Виртуальное наследование (virtual inheritance) предотвращает появление множественных объектов базового класса в иерархии наследования. Таким образом, конструктор базового класса Device будет вызван только единожды, а обращение к методу turn_on() без его переопределения в дочернем классе не будет вызывать ошибку при компиляции.

Примечание: виртуальное наследование в классах Computer и Monitor не разрешит ромбовидное наследование если дочерний класс Laptop будет наследовать класс Device не виртуально ( class Laptop: public Computer, public Monitor, public Device <>; ).

Абстрактный класс

В С++, класс в котором существует хотя бы один чистый виртуальный метод (pure virtual) принято считать абстрактным. Если виртуальный метод не переопределен в дочернем классе, код не скомпилируется. Также, в С++ создать объект абстрактного класса невозможно — попытка тоже вызовет ошибку при компиляции.

Интерфейс

С++, в отличии от некоторых ООП языков, не предоставляет отдельного ключевого слова для обозначения интерфейса (interface). Тем не менее, реализация интерфейса возможна путем создания чистого абстрактного класса (pure abstract class) — класса в котором присутствуют только декларации методов. Такие классы также часто называют абстрактными базовыми классами (Abstract Base Class — ABC).

Advanced

Несмотря на то, что наследование — фундаментальный принцип ООП, его стоит использовать с осторожностью. Важно думать о том, что любой код который будет использоваться скорее всего будет изменен и может быть использован неочевидным для разработчика путем.

Наследование от реализованного или частично реализованного класса

Если наследование происходит не от интерфейса (чистого абстрактного класса в контексте С++), а от класса в котором присутствуют какие-либо реализации, стоит учитывать то, что класс наследник связан с родительским классом наиболее тесной из возможных связью. Большинство изменений в классе родителя могут затронуть наследника что может привести к непредвиденному поведению. Такие изменения в поведении наследника не всегда очевидны — ошибка может возникнуть в уже оттестированом и рабочем коде. Данная ситуация усугубляется наличием сложной иерархии классов. Всегда стоит помнить о том, что код может изменяться не только человеком который его написал, и пути наследования очевидные для автора могут быть не учтены его коллегами.

В противовес этому стоит заметить что наследование от частично реализованных классов имеет неоспоримое преимущество. Библиотеки и фреймворки зачастую работают следующим образом: они предоставляют пользователю абстрактный класс с несколькими виртуальными и множеством реализованных методов. Таким образом, наибольшее количество работы уже проделано — сложная логика уже написана, а пользователю остается только кастомизировать готовое решение под свои нужды.

Интерфейс

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

Интерфейс: Пример использования

Прежде всего стоит заметить, что пример тесно связан с понятием полиморфизма, но будет рассмотрен в контексте наследования от чистого абстрактного класса.

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

Отсутствие однозначности касательно форматирования конфигурационного файла не тормозит процесс разработки основной программы. Два разработчика могут работать параллельно — один над бизнес логикой, а другой над парсером. Поскольку они взаимодействуют через этот интерфейс, каждый из них может работать независимо. Данный подход облегчает покрытие кода юнит тестами, так как необходимые тесты могут быть написаны с использованием мока (mock) для этого интерфейса.

Также, при изменении формата конфигурационного файла, бизнес логика приложения не затрагивается. Единственное чего требует полный переход от одного форматирования к другому — написания новой реализации уже существующего абстрактного класса (класса-парсера). В дальнейшем, возврат к изначальному формату файла требует минимальной работы — подмены одного уже существующего парсера другим.

Заключение

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *