ИГА. Понятие базы данных
Скачать 0.77 Mb.
|
Реализация методов класса. Конструкторы и деструкторы.При создании объекта класса его члены инициализируются с помощью специального метода, который называется конструктором. Исполняющая система C++ сначала захватывает область памяти под объект (в стеке или в куче, в зависимости от того, как создается объект). Затем вызывается конструктор объекта, которому передается адрес этой области памяти. Назначение конструктора -- установить начальные значения членов класса, а также выполнить необходимые начальные действия при создании объекта. Имя конструктора совпадает с именем класса. Конструктор может иметь аргументы, может быть несколько конструкторов с разными наборами аргументов. Стандарт языка не накладывает никаких ограничений на возможные действия в конструкторе, так что можно написать целую содержательную программу внутри конструктора. Но это дурной стиль! Никогда не делайте ничего содержательного в конструкторе, ограничивайтесь только начальной инициализацией. Если это не так, то постоянно будут возникать проблемы с описанием временных переменных, с наследованием классов, с возвратом значений функций и методов и т.п. К примеру, во всякой оконной системе конструктор класса "Окно" не создает окна на экране. Для того, чтобы окно появилось на экране, требуется вызвать специальные методы вроде "Create", "ShowWindow", "Map" и т.п. Итак, в конструкторе нужно лишь инициализировать переменные и при необходимости захватывать память в куче, если какие-то члены класса являются указателями. Аналогично при удалении объекта вызывается специальный метод, который называется деструктором. Деструктор вызывается непосредственно перед освобождением памяти, занятой объектом. Крайне дурным стилем является выполнение каких-либо содержательных действий в деструкторе! Например, сохранение информации в файле на диске не следует помещать в деструктор, для этого используют специальный метод вроде "save". В деструкторе чаще всего выполняется только одно действие: освобождение динамической памяти, захваченной в конструкторе или в других методах класса. Делается это тогда, когда объект класса содержит указатели на области динамической памяти. Реализация объемных (не инлайновых) методов класса выносится из заголовочного файла в файл реализации, который называют C++ файлом. К сожалению, в отличие от h-файлов программисты не сумели договориться между собой о стандартном расширении для C++ файлов. В разных операционных системах и разных системах разработки используются расширения ".cpp", ".cxx", ".cc" и другие. Стандарт языка не устанавливает никаких явных правил на этот счет. Обычно все конкретные компиляторы понимают по умолчанию перечисленные выше расширения как расширения файлов, содержащих программы на C++. Но компилятор можно явным образом заставить трактовать программу как программу на C++ независимо от расширения файла. Например, в случае компилятора "gcc" можно использовать ключ "-x": Полиморфизм, перегрузка методов.Полиморфизм – возможность объектов с одинаковой спецификацией иметь различную реализацию. Полиморфизм позволяет писать более абстрактные программы и повысить коэффициент повторного использования кода, потому что общие свойства объектов объединяются в одну систему [6]. Общность этой систему имеет внешнее и внутреннее выражение: Внешняя – одинаковый набор методов с одинаковыми именами и/или сигнатурами (имена методов, типы аргументов и их количество) Внутренняя – одинаковая функциональность методов В C++ полиморфизм реализуется с помощью наследования классов и виртуальных функций. Класс-потомок наследует сигнатуры методов класса-родителя, а реализация, в результате переопределения может быть другой, соответствующей специфике класса-потомка. В результате, можно работать с объектом как с экземпляром класса-родителя, но если при этом объект на самом деле является экземпляром класса-потомка, то во время исполнения будет вызван метод, переопределенный в классе-потомке Принцип наследования. Виртуальные и абстрактные методы.Для сокращения объема исходного кода и лучшей структуризации объектно-ориентированное программирование предлагает механизм наследования. Наследование – это отношение между классами, при котором один класс разделяет структуру и поведение одного или нескольких классов. Важно отметить, что говоря о наследовании, может употребляться «является». Объект наследника «является» объектом наследуемого класса, т.к. он обладает всеми атрибутами и методами родителя. Однако это поведение может быть изменено при наследовании путем использования полиморфизма и инкапсуляции [12]. Имеется более точное определение наследования как классификации. Для метода определяется условие, при котором он может выполняться (предусловие) и условие, истинное при выполнении контракта (постусловие). Для того, чтобы наследование считалось классификацией (или строгим наследованием), необходимо [11]: для каждого метода порожденного класса его предусловие слабее, чем предусловие соответствующего метода родительского класса для каждого метода порожденного класса его постусловие сильнее, чем постусловие соответствующего метода родительского класса инварианты базовых классов являются подмножествами инварианта порожденного класса Важно отметить, что иногда наследование характеризуют как отношения обобщения, т.к. наследник разделяет атрибуты и методы своих родителей (некоторые объектно-ориентированные языки программирования разрешают множественное наследование). В C++ абстрактные классы – классы с одним или более абстрактным методом или наследующие их. Важно отметить, что невозможно создать объект абстрактного класса. Абстрактные методы (чисто виртуальные функции) получаются добавлением чистого описателя (=0) в определение метода. Эти методы специально предназначены для наследования, и их реализация должна быть определена в классах-потомках. В C++ полиморфизм реализуется с помощью наследования классов и виртуальных функций. Класс-потомок наследует сигнатуры методов класса-родителя, а реализация, в результате переопределения может быть другой, соответствующей специфике класса-потомка. В результате, можно работать с объектом как с экземпляром класса-родителя, но если при этом объект на самом деле является экземпляром класса-потомка, то во время исполнения будет вызван метод, переопределенный в классе-потомке |