Наследование Наследование в























Наследование
Наследование в С++ - это механизм, посредством которого один класс может наследовать свойства другого. Наследование позволяет строить иерархию классов, переходя от более общих к более специальным. Когда один класс наследуется другим, класс, который наследуется, называется базовым классом. Наследующий класс называют производным классом.
Когда применяется? Наследование применяется для следующих взаимосвязанных целей: • исключения из программы повторяющихся фрагментов кода; • упрощения модификации программы; • упрощения создания новых программ на основе существующих; • возможность использовать объекты, исходный код которых недоступен, но в которые требуется внести изменения;
Синтаксис наследования Ключи(модификаторы) доступа class имя : [private | protected | public] базовый_класс { тело класса }; class A {. . . }; class B {. . . }; class C {. . . }; class D: A, protected B, public C {. . . };
Что можно сделать? В наследнике можно описывать новые поля и методы и переопределять существующие методы. Переопределять методы можно несколькими способами: Ø Если какой-либо метод в потомке должен работать совершенно по-другому, чем в предке, метод описывается в потомке заново. При этом он может иметь другой набор аргументов. Ø Если требуется внести добавления в метод предка, то в соответствующем методе потомка наряду с описанием дополнительных действий выполняется вызов метода предка с помощью операции доступа к области видимости. Если в программе планируется работать одновременно с различными типами объектов иерархии или планируется добавление в иерархию новых объектов, метод объявляется как виртуальный с помощью ключевого слова virtual. Все виртуальные методы иерархии с одним и тем же именем должны иметь одинаковый список аргументов.
Модификаторы наследования Модификатор наследования определяет видимость наследуемых переменных и методов private (собственный) public (общедоступный) protected (защищенный)
Правила наследования Ключ доступа Спецификатор в Доступ в базовом классе производном классе private нет protected private public private protected private нет protected public protected public private нет protected public
Модификаторы наследования Protected Модификатор protected используется тогда, когда необходимо, чтобы некоторые члены базового класса оставались закрытыми, но были бы доступны для производного класса. Protected эквивалентен private с единственным исключением: защищенные члены базового класса доступны для членов всех производных классов этого базового класса.
Модификаторы наследования private элементы базового класса в производном классе недоступны вне зависимости от ключа. Обращение к ним может осуществляться только через методы базового класса. Элементы protected при наследовании с ключом private становятся в производном классе private, в остальных случаях права доступа к ним не изменяются. Доступ к элементам public при наследовании становится соответствующим ключу доступа.
Конструкторы и деструкторы при наследовании Если в конструкторе потомка явный вызов конструктора предка отсутствует, автоматически вызывается конструктор предка по умолчанию Если и у базового и у производного классов есть конструкторы и деструкторы, то конструкторы выполняются в порядке наследования, а деструкторы - в обратном порядке. Если А базовый класс, В - производный из А, а С - производный из В (А-В-С), то при создании объекта класса С вызов конструкторов будет иметь следующий порядок: конструктор А - конструктор В - конструктор С. Вызов деструкторов при разрушении этого объекта произойдет в обратном порядке: деструктор С - деструктор В - деструктор А. В случае нескольких предков их конструкторы вызываются в порядке объявления.
Пример Класс - точка на экране Описание: class Point { protected: int x; int y; bool visible; public: int Get. X(void) { return x; } int Get. Y(void) { return y; } bool Is. Visible (){ return visible; } Point (const Point& cp); // прототип конструктора копирования Point (int new. X =0, int new. Y =0); // прототип конструктора }; Point : : Point (int new. X, int new. Y) // конструктор { x = new. X; y = new. Y; visible = false; } Point : : Point (const Point& cp) // конструктор копирования { x = cp. x; y = cp. y; visible = cp. visible; }
Пример Дополним класс методами для отображения на экране class Point { . . . public: . . . void Show(); void Hide(); void Move. To(int new. X, int new. Y); }; void Point: : Show() { visible = true; putpixel (x, y, getcolor()); } void Point: : Hide() { visible = false; putpixel (x, y, getbkcolor()); } void Point: : Move. To (int new. X, int new. Y) { Hide (); x = new. X; y = new. Y; Show (); }
Пример Класс Point Можно создавать объекты-точки, высвечивать, гасить и перемещать их по экрану Создадим класс Окружность
Пример class Circle: public Point { int radius; // private по умолчанию public: Circle (int init. X, int init. Y, int init. R); void Show (); void Hide (); void Expand (int delta. R); void Contract (int delta. R); void Move. To (int new. X, int new. Y); };
Пример Circle: : Circle (int init. X, int init. Y, int init. R) // конструктор : Point (init. X, init. Y) // вызов конструктора void Circle: : Expand (int delta. R) базового класса { { Hide(); radius = init. R; radius += delta. R; } Show(); void Circle: : Show () } { void Circle: : Contract (int delta. R) visible = true; { circle (x, y, radius); Expand (-delta. R); } } void Circle: : Hide () // скрыть = зарисовать void Circle: : Move. To (int new. X, цветом фона int new. Y) { { visible = false; Hide (); unsigned int temp. Color = getcolor (); x = new. X; setcolor (getbkcolor()); y = new. Y; circle (x, y, radius); Show (); setcolor (temp. Color); } }
Пример main() { int graph. Dr = DETECT, graph. Mode; initgraph ( &graph. Dr, &graph. Mode, ""); Circle C (150, 200, 50); // создать объект окружность с центром в т. (150, 200) и радиуса 50 C. Show(); // показать окружность getch(); C. Move. To (300, 100); // переместить getch(); C. Expand (50); // растянуть getch(); C. Contract (70); // сжать getch(); closegraph(); }
Виртуальные методы virtual void draw(int x, int y, int scale, int position); monstr *r, *p; // Создается объект класса monstr r = new monstr; // Создается объект класса daemon vtbl p = new daemon; // Вызывается метод monstr: : draw vptr r->draw(1, 1, 1, 1); // Вызывается метод daemon: : draw p->draw(1, 1, 1, 1); // Обход механизма виртуальных методов p-> monstr: : draw(1, 1, 1, 1);
Описание и использование виртуальных методов l. Если в предке метод определен как виртуальный, метод, определенный в потомке с тем же именем и набором параметров , автоматически становится виртуальным, а с отличающимся набором параметров — обычным. l. Виртуальные методы наследуются , то есть переопределять их в потомке требуется только при необходимости задать отличающиеся действия. Права доступа при переопределении изменить нельзя. l. Если виртуальный метод переопределен в потомке, объекты этого класса могут получить доступ к методу предка с помощью операции доступа к области видимости. l. Виртуальный метод не может объявляться с модификатором static , но может быть объявлен как дружественный. l. Если в классе вводится объявление виртуального метода, он должен быть определен хотя бы как чисто виртуальный.
Чисто виртуальные методы - содержит признак = 0 вместо тела: virtual void f(int) = 0; - должен переопределяться в производном классе. Класс, содержащий хотя бы один чисто виртуальный метод, называется абстрактным. lабстрактный класс нельзя использовать при явном приведении типов, для описания типа параметра и типа возвращаемого функцией значения; lдопускается объявлять указатели и ссылки на абстрактный класс, если при инициализации не требуется создавать временный объект; lесли класс, производный от абстрактного, не определяет все чисто виртуальные функции, он также является абстрактным.
Множественное наследование class monstr{ public: int get_health(); . . . }; class hero{ public: int get_health(); . . . }; class ostrich: public monstr, public hero {. . . }; int main(){ ostrich A; cout << A. monstr: : get_health(); cout << A. hero: : get_health(); }
monstr class monstr{ . . . }; class daemon: virtual public monstr{ . . . daemon lady }; class lady: virtual public monstr{ . . . }; baby class baby: public daemon, public lady{ . . . };
Рекомендации Множественное наследование применяется для того, чтобы обеспечить производный класс свойствами двух или более базовых. Чаще всего один из этих классов является основным, а другие обеспечивают некоторые дополнительные свойства, поэтому они называются классами подмешивания. По возможности классы подмешивания должны быть виртуальными и создаваться с помощью конструкторов без параметров, что позволяет избежать многих проблем, возникающих, когда у базовых классов есть общий предок.
Виды отношений между классами ассоциация (два класса концептуально взаимодействуют друг с другом); наследование (отношение обобщения, «is a» ); агрегация (отношение целое/часть, «has a» ); строгая (композиция) нестрогая (по ссылке) зависимость (отношение использования)

