Определение производного класса
В определении и описании производного класса приводится список базовых классов, из которых он непосредственно наследует данные и методы. Между именем вводимого (нового) класса и списком базовых классов помещается двоеточие. Например, при таком определении
class S: X, Y, Z { ...};
класс S порожден классами X, Y, Z, откуда он наследует компоненты. Наследование компонента не выполняется, если его имя будет использовано в качестве имени компонента в определении производного класса S. Как уже говорилось, по умолчанию из базовых классов наследуются методы и данные со спецификаторами доступа - public (общедоступные) и protected (защищенные).
В порожденном классе эти унаследованные компоненты получают статус доступа private, если новый класс определен с помощью ключевого слова class, и статус доступа public, если новый класс определен как структура, т.е. с помощью ключевого слова struct. Таким образом при определении класса
struct J : X, Z { ... };
любые наследуемые компоненты классов X, Z будут иметь в классе J статус общедоступных (public). Пример:
class B {protected: int t;public: char u;};class E: B { ... }; // t и u наследуются как privatestruct S: B { ... }; // t и u наследуются как publicЯвно изменить умалчиваемый статус доступа при наследовании можно с помощью спецификаторов доступа - private, protected и public. Эти спецификаторы доступа указываются в описании производного класса непосредственно перед нужными именами базовых классов. Если класс B определен так, как показано выше, то можно ввести следующие производные классы:
class M: protected B { ... }; // t, u наследуется как protectedclass P: public B { ... }; // t - protected, u - publicclass D: private B { ... }; // t, u наследуется как privatestruct F: private B { ... }; // t, u наследуется как privatestruct G: public B { ... }; // t - protected, u - publicКонструктор базового класса всегда вызывается и выполняется до конструктора производного класса.
Особенности деструкторов
Итак, конструктор вызывается при создании каждого объекта класса и выполняет все необходимые операции как для выделения памяти объекта, так и для ее инициализации. Когда объект уничтожается при завершении программы или при выходе из области действия определения соответствующего класса, необходимы противоположные операции, самая важная из которых - освобождение памяти. Эти операции могут и должны выполняться по-разному в зависимости от особенностей конкретного класса. Поэтому в определении класса явно или по умолчанию включают специальную принадлежащую классу функцию - деструктор. Деструктор имеет строго фиксированное имя вида:
~имя_класса.
У деструктора не может быть параметров (даже типа void), и деструктор не имеет возможности возвращать какой-либо результат, даже типа void. Статус доступа деструктора по умолчанию public (т.е. деструктор доступен во всей области действия определения класса). В несложных классах деструктор обычно определяется по умолчанию.
Деструкторы не наследуются, поэтому даже при отсутствии в производном классе деструктора он не передается из базового, а формируется компилятором как умалчиваемый со статусом доступа public. Этот деструктор вызывает деструкторы базовых классов.
В любом классе могут быть в качестве компонентов определены другие классы. В этих классах будут свои деструкторы, которые при уничтожении объекта охватывающего (внешнего) класса выполняются после деструктора охватывающего класса.
Деструкторы базовых классов выполняются в порядке, обратном перечислению классов в определении производного класса. Таким образом порядок уничтожения объекта противоположен по отношению к порядку его конструирования.
Вызовы деструкторов для объектов класса и для базовых классов выполняются неявно и не требуют никаких действий программиста. Однако вызов деструктора того класса, объект которого уничтожается в соответствии с логикой выполнения программы, может быть явным. Это может быть, например, случай, когда при создании объекта для него явно выделялась память.