Особенности наследования классов
Цели объектно-ориентированного программирования, абстрактные классы и адреса базовых классов, множественное и виртуальное наследование. Инициализация элементов производного класса. Программный вызов конструкторов базового и производного классов.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | реферат |
Язык | русский |
Дата добавления | 30.10.2011 |
Размер файла | 83,3 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
Особенности наследования классов
Содержание
наследование производный класс конструктор
Введение
1. Абстрактные классы
2. Множественное наследование
3. Адреса базовых классов
4. Виртуальное наследование
Заключение
Список литературы
Введение
Цель объектно-ориентированного программирования состоит в повторном использовании созданных вами классов, что экономит ваше время и силы. Если вы уже создали некоторый класс, то возможны ситуации, что новому классу нужны многие или даже все особенности уже существующего класса, и необходимо добавить один или несколько элементов данных или функций. В таких случаях C++ позволяет вам строить новый объект, используя характеристики уже существующего объекта. Другими словами, новый объект будет наследовать элементы существующего класса (называемого базовым классом). Когда вы строите новый класс из существующего, этот новый класс часто называется производным классом. В этом уроке впервые вводится наследование классов в C++.
Ели ваши программы используют наследование, то для порождения нового класса необходим базовый класс, т.е. новый класс наследует элементы базового класса.
Для инициализации элементов производного класса ваша программа должна вызвать конструкторы базового и производного классов. Используя оператор точку, программы могут легко обращаться к элементам базового и производного классов.
Для разрешения конфликта имен между элементами базового и производного классов ваша программа может использовать оператор глобального разрешения, указывая перед ним имя базового или производного класса.
Наследование является фундаментальной концепцией объектно-ориентированного программирования. Выберите время для экспериментов с программами, представленными в этом уроке. И вы обнаружите, что реально наследование реализуется очень просто и может сохранить огромные усилия, затрачиваемые на программирование.
1. Абстрактные классы
Абстрактным называется класс, который содержит как минимум одну чистую виртуальную компонентную функцию. Чистая виртуальная функция - это виртуальная функция, для которой программист не планирует в текущей версии программы иметь каких-либо реализаций. Объявление такой функции может иметь, например, следующий вид:
class Employee { // Класс “Служащий”
private:
char name[40]; // Имя служащего
public:
Employee(char* n);
//Чистая виртуальная функция
virtual void* promote( )=0;
Абстрактный класс не может быть реализован в объекте. Так, следующая строка:
Employee s("My name");
вызовет ошибку, о которой сообщит компилятор.
Однако программа может объявить указатель абстрактного класса, так что следующая строка вполне допустима:
Employee* sPtr;
Компоненты абстрактного класса могут наследоваться. Если все чистые виртуальные методы класса перегружены правилами, не являющимися чистыми и виртуальными, класс может не являться абстрактным. В следующем примере класс Secretary может быть реализован объектом, поскольку функция promote была перегружена и имеет теперь другой смысл.
class Secretary : public Employee {
private:
int moreData;
public:
Secretary(char* n) : Employee(n) { }
virtual void* promote( );
};
Secretary sec("Another Name");
Адрес объекта Secretary может быть передан в функцию, которая ожидает передачи Employee:
void fn(Employee*);
Secretary sec("Another Name");
fn(&sec);
Абстрактные классы полезны для организации иерархической структуры классов. Например, может быть известно, что все служащие должны принадлежать к подклассу Employee.
Поскольку разные служащие имеют разные циклы продвижения по службе (promotion), каждый подкласс должен иметь собственный метод promote. Объявив promote как чистую виртуальную функцию, разработчик класса Employee требует тем самым, чтобы разработчик подкласса написал метод promote до реализации любого производного класса от Employee.
2. Множественное наследование
Наследование представляет собой способность производного класса наследовать характеристики существующего базового класса. Простыми словами это означает, что, если у вас есть класс, чьи элементы данных или функции-элементы могут быть использованы новым классом, вы можете построить этот новый класс в терминах существующего (или базового) класса. Новый класс в свою очередь будет наследовать элементы (характеристики) существующего класса. Использование наследования для построения новых классов сэкономит вам значительное время и силы на программирование. Объектно-ориентированное программирование широко использует наследование, позволяя вашей программе строить сложные объекты из небольших легко управляемых объектов.
В C++ класс может наследовать свойства более чем одного класса. Формат определения наследования классом свойств нескольких базовых классов аналогичен формату определения наследования свойств отдельного класса. Приведем пример.
class SubClass : public Base1, private Base2 {
// остальная часть определения класса
}
В определении может быть перечислено любое число базовых классов через запятую. Ни один базовый класс не может быть прямо унаследован более одного раза. Каждый базовый класс может быть унаследован как public или как private; умолчанием является private.
Когда класс мог наследовать свойства только одного единственного класса, последовательность выполнения конструкторов не являлась жестко заданной. С переходом к множественному наследованию порядок выполнения конструкторов становится очень важен. Этот порядок вызова следующий:
(1) конструкторы всех виртуальных базовых классов; если их имеется более одного, то конструкторы вызываются в порядке их наследования;
(2) конструкторы невиртуальных базовых классов в порядке их наследования;
(3) конструкторы всех компонентных классов.
Рассмотрим следующий пример.
#include <iostream.h>
struct Base1 {
Base1( ) { cout<< "Создание Base1"<<endl; }
};
struct Base2 {
Base2( ) { cout<< "Создание Base2"<<endl; }
};
struct Base3 {
Base3( ) { cout<< "Создание Base3"<<endl; }
};
struct Base4 {
Base4( ) { cout<< "Создание Base4"<<endl; }
};
struct Derived : private Base1, private Base2,private Base3 {
Base4 anObject;
Derived( ) {}
};
void main( ) {
Derived anObject;
}
На выходе этой программы будет следующее:
Создание Base1
Создание Base2
Создание Base3
Создание Base4
Добавление в конструктор для Derived конкретных вызовов с другим порядком и повторение программы не изменит сообщения после выполнения этой программы.
struct Derived : private Base1, private Base2, private Base3 {
Base4 anObject;
Derived( ) : anObject( ), Base3( ), Base2( ), Base1( ) {}
};
Изменение порядка наследования классов изменит последовательность появления сообщений на выходе программы. Объявив Derived следующим образом:
struct Derived : private Base3, private Base2, private Base1 {
Base4 anObject;
Derived( ) : anObject( ), Base1( ), Base2( ), Base3( ) {}
};
можно получить на выходе программы:
Создание Base3
Создание Base2
Создание Base1
Создание Base4
Последовательность вызова деструкторов будет обратной относительно последовательности вызова конструкторов.
Необходимость использования в программе множественного наследования чаще всего говорит о плохой структуризации классов. Это могло возникнуть в том случае, если программист уделил недостаточно времени для предварительного анализа предметной области программы на самом первом этапе ее составления. Структурный подход к объектно-ориентированному проектированию предполагает более четкую организацию классов.
3. Адреса базовых классов
Большое число проблем при проектировании объектно-ориентированных программ возникает в связи со способом размещения производных классов в памяти. Одна из ключевых причин того, что указатель подкласса может передаваться как указатель суперкласса, состоит в том, что когда-то суперкласс впервые появляется в подклассе. Рассмотрим простой пример наследования в классах.
struct Base {
int a;
float b;
void f1( );
};
struct Derived : public Base {
int c;
} object;
Рассматривая размещение объекта производного класса Derived в памяти, например, с помощью команды отладчика Inspect, можно получить несколько упрощенную графическую диаграмму, которая приведена на рис.1.
Рис. 1. Схема размещения в памяти простого производного класса
Если Derived* передан в функцию, ожидающую получения Base*, никаких проблем не возникает. Класс Derived совпадает с классом Base во всем, что касается его части, перекрывающейся с Base. То же самое касается и вызова функции object.f1. Передаваемый указатель this имеет одно и то же значение безотносительно к типу. Однако в отношении класса Derived с множественным наследованием сказанное ранее будет несправедливо.
Рассмотрим пример.
struct Base1 {
int a; float b;
void f1( );
};
struct Base2 {
int c;
float d;
void f2( );
};
struct Derived : public Base1, public Base2 {
int e;
} object;
Примерная схема памяти для этого случая показана на рис. 2.
Класс Base2 более не находится в начале класса Derived. Если попробовать передать Derived* функции, ожидающей поступления Base1*, то проблем не возникнет. Вместе с тем, при вызове функции, ожидающей поступления Base2*, полученный ей адрес окажется неправильным.
Чтобы исправить этот адрес, необходимо прибавить к адресу Derived:object смещение Base2 в Derived, таким образом, чтобы результат указывал на ту часть, которая относится к Base2. Такая же коррекция должна выполняться для каждого случая приведения типа указателей из Derived* в Base2*, включая и скрытый указатель this, передаваемый компонентным функциям Base2.
Рис. 2. Схема размещения в памяти класса с множественным наследованием
Derived object;
object.f2( ) // Перед передачей в f2( ) адрес объекта object
// должен быть соответственно скорректирован
По тем же причинам C++ также должен выполнить коррекцию и при обратном приведении типа из Base2* в Derived*.
4. Виртуальное наследование
В следующем примере класс Derived наследует свойства двух копий класса Base: одной через класс FirstBase, а второй - через SecondBase:
struct Base {
int object;
};
struct FirstBase : public Base {
int a;
};
struct SecondBase : public Base {
float b;
};
class Derived : public FirstBase, public SecondBase {
long dObject;
};
Примерная схема памяти для объекта класса Derived показана на рис. 3.
Рис. 3. Схема размещения в памяти множественного
производного класса
Чтобы позволить наследование в таких случаях одной и той же копии Base, в C++ необходимо включить в команду наследования ключевое слово virtual. В этом случае, программу можно переписать следующим образом:
struct Base {
int object;
};
struct FirstBase : virtual public Base {
int a;
};
struct SecondBase : virtual public Base {
float b;
};
class Derived : virtual public FirstBase,
virtual public SecondBase {
long dObject;
};
Такая модификация программы изменит схему размещения объекта класса Derived, как показано на рис. 4.
Рис. 4. Схема размещения в памяти виртуального множественного производного класса
Заключение
Наследование в C++ позволяет вам строить /порождать) новый класс из существующего класса. Строя таким способом один класс из другого, вы уменьшаете объем программирования, что, в свою очередь, экономит ваше время. C++ позволяет вам порождать класс из двух или нескольких базовых классов. Использование нескольких базовых классов для порождения класса представляет собой множественное наследование. В заключении можно сделать следующие выводы:
1. Наследование представляет собой способность производить новый класс из существующего базового класса.
2. Производный класс -- это новый класс, а базовый класс -- существующий класс.
3. Когда вы порождаете один класс из другого (базового класса), производный класс наследует элементы базового класса.
4. Для порождения класса из базового начинайте определение производного класса ключевым словом class, за которым следует имя класса, двоеточие и имя базового класса, например class dalmatian: dog.
5. Когда вы порождаете класс из базового класса, производный класс может обращаться к общим элементам базового класса, как будто эти элементы определены внутри самого производного класса. Для доступа к частным данным базового класса производный класс должен использовать интерфейсные функции базового класса.
6. Внутри конструктора производного класса ваша программа должна вызвать конструктор базового класса, указывая двоеточие, имя конструктора базового класса и соответствующие параметры сразу же после заголовка конструктора производного класса.
7. Чтобы обеспечить производным классам прямой доступ к определенным элементам базового класса, в то же время защищая эти элементы от оставшейся части программы, C++ обеспечивает защищенные (protected) элементы класса. Производный класс может обращаться к защищенным элементам базового класса, как будто они являются общими. Однако для оставшейся части программы защищенные элементы эквивалентны частным.
8. Если в производном и базовом классе есть элементы с одинаковым именем, то внутри функций производного класса C++ будет использовать элементы производного класса. Если функциям производного класса необходимо обратиться к элементу базового класса, вы должны использовать оператор глобального разрешения, например base class:: member.
Список литературы
1) Т. Сван. Освоение Borland C++ 4.5: Пер. с англ. - Киев: Диалектика, 1996. 544с.
2) Г. Шилдт. Самоучитель C++: Пер. с англ. - Санкт-Петербург: BHV-Санкт-Петербург, 1998. 620с.
3) У. Сэвитч. C++ в примерах: Пер. с англ. - Москва: ЭКОМ, 1997. 736с.
4) К. Джамса. Учимся программировать на языке C++: Пер. с англ. - Москва: Мир, 1997. 320с.
5) В.А. Скляров. Язык C++ и объектно-ориентированное программирование: Справочное издание. - Минск: Вышэйшая школа, 1997. 480с.
6) Х. Дейтел, П. Дейтел. Как программировать на C++: Пер. с англ. - Москва: ЗАО "Издательство БИНОМ", 1998. 1024с.
Размещено на Allbest
Подобные документы
Цели объектно-ориентированного программирования, абстрактные классы и адреса базовых классов, множественное и виртуальное наследование. Инициализация элементов производного класса, программный вызов конструкторов базового и производного классов.
реферат [21,8 K], добавлен 31.10.2011Иерархия и типы классов в программе, особенности обеспечения наследования. Наследование по принципу подчиненности. Включение в другие классы или делегирование. Понятие изолированных классов. Конструкторы и деструкторы. Иерархия классов NET Framework.
презентация [91,8 K], добавлен 09.12.2013Изучение принципов объектно-ориентированного программирования. Понятие класса в Delphi, в основе которых лежат три фундаментальные принципы - инкапсуляция, наследование и полиморфизм. Разработка классов транспортных средств и структур классов (кошки).
курсовая работа [29,7 K], добавлен 29.10.2011Классы и свойства объектно-ориентированного пространства. Методика создания новых классов в delphi: выбор родительского класса, изменение существующих компонентов, создание подклассов для элементов управления windows. Создание новой ветви классов.
контрольная работа [13,0 K], добавлен 07.07.2012Анализ объектно-ориентированного программирования, имитирующего способы выполнения предметов. Основные принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм. Понятие классов, полей, методов, сообщений, событий.
контрольная работа [51,7 K], добавлен 22.01.2013Объектно-ориентированный язык программирования: общая характеристика и свойства. Базовый и производный классы, конструкторы производного класса. Конструкторы и неопределенность при множественном наследовании. Роль наследования при разработке программ.
курсовая работа [688,3 K], добавлен 23.12.2013Изучение принципов объектно-ориентированного программирования, в котором основными концепциями являются понятия классов и объектов. Свойства этого вида программирования: инкапсуляция, полиморфизм, наследование. Описание класса. Конструкторы и деструкторы.
презентация [74,8 K], добавлен 14.10.2013Классы, объекты и объектные ссылки. Особенности статических методов. Конструкторы, специальные переменные, наследование. Создание объектов внутренних классов. Соглашения об именовании. Некоторые методы класса Object. Абстрактные классы и атрибуты.
лекция [130,6 K], добавлен 21.06.2014Методология объектно-ориентированного программирования в Java. Понятия класса, объекта и объектной переменной. Динамическая и статическая объектные модели. Логическое структурирование приложения. Наследование в Java. Отличия интерфейсов от классов.
курс лекций [547,2 K], добавлен 01.05.2014Объектно-ориентированный подход к проектированию программных систем. Простое наследование и доступ к наследуемым компонентам. Конструкторы производных классов, объемлющие классы, понятие об алгоритме и операторе. Примеры реализации связных списков.
реферат [24,5 K], добавлен 31.10.2011