Виртуални функции и абстрактни класове

Лекция 18. Множествено наследяване

А клас, могат да бъдат генерирани от всеки брой базови класове. Наличието на повече от един непосредствен базовия клас се нарича множествено наследяване.






клас А;
клас В;
клас С;
клас D. обществен A, B обществен, частен С;

Указател към извлечения клас може да бъде прехвърлено към функция, която очаква указател към една от основните класове. Изпълнението на този механизъм включва проста компилация от техники, за да се гарантира, че функция, която очаква указател към базов клас, вижте тази част от новия клас, различен от този, който ще видите, че функцията очаква указател към друг базов клас. Виртуалните функции работят както обикновено.
клас А ; клас B ; клас C: обществен A, B обществен ; невалидни f1 (A * р) f1 ();> невалидни f2 (р B *) f2 ();> невалидни основни () д (); // Правилно р-> Н (); // грешка: з функция не е член на клас А dynamic_cast (Р) -> Н (); // Правилно>

Класът не може да бъде определен като непосредствен базов клас повече от един път, но може да бъде повече от веднъж индиректно базов клас.

клас А <.>; клас Б: обществен А, обществен А;

клас А <.>; клас Б: обществен А; клас C: обществен А; клас D: обществен B, C публичен;

Тук съоръжение за клас D ще има два под-обект от клас А.

Полученият класа и неговите основни класове могат да бъдат представени като насочена ациклични графика.

Тъй като обект D има две задействане обект А. (изрично или мълчаливо) между А и указател към указател към D неясна и поради това са забранени.

D * Pd = нов D; А * PA = Pd; PA = (А *) Pd; PA = (B *) Pd; PA = (С *) Pd;

// неяснота! // Всички същия неяснотата! // Намаляване към указател към обект Б // Намаляване на указател към обект В.

Въпреки това, този клас може да бъде както пряка и непряка базов клас.

клас А <.>; клас Б: обществен A <.>; клас C: обществен A <.>; клас D: обществен A, B обществен, обществен C <.>; PA = Pd; PA = (B *) Pd; PA = (С *) Pd;

// може повече! // Събирането указател към обекта А веднага D // Намаляване към указател към обект Б // Намаляване на указател към обект В.

// функция A :: е (междинно съединение) става отворен

// наричаме функция A :: F (ср) // Call функция В1 :: е (двойно) // повикване функция В2 :: е (знак) // повикване функция C :: е (знак *)

Чрез дескриптора на базовия клас, можете да добавите виртуалното ключова дума.
клас А <.>; клас Б: виртуална публична A <.>; клас C: виртуална публична A <.>; клас D: обществен B, C обществен <.>;

В този случай, клас D има само един екземпляр на клас А. Графично, то изглежда така:

А клас може да съдържа и двете виртуални и не-виртуален базов клас от този тип.
клас А <.>; клас Б: виртуална публична A <.>; клас C: виртуална публична A <.>; клас D: обществен A <.>; клас Е: обществен B, C обществен, обществен D <.>;

Тук Е клас включва две копия на клас А. D. един клас и друг клас виртуална общи класове А. В и С.

клас А <.>; клас Б: виртуална публична A <.>; клас C: виртуална публична A <.>; клас D: обществен A, B обществен, обществен C <.>;

// Вие не можете! Привеждане в клас А е двусмислен.

При определяне на характеристики клас с виртуален базов клас програмист, като цяло, не можем да знаем дали базовия клас се използва в комбинация с други класове. То може да бъде някакъв проблем с изпълнението на алгоритмите, които изискват, че функцията на базовия клас се нарича точно веднъж. Език осигурява виртуален базов клас конструктор се нарича само веднъж. Конструктор нарича виртуален базов клас (пряко или косвено) от конструктор на обекта (строителя на "долната" извлечения клас).
клас А >; клас В1: виртуална публична A >; клас B2: виртуална публична A >; клас C: обществен B1, B2 обществен >; клас А >; клас В1: обществен A >; клас B2: обществен A >; клас C: обществен B1, B2 обществен >;

Ако е необходимо, програмист може да симулира тази схема, вкарвайки на база клас виртуална функция само на "нисш", получен клас.

Извлечен клас може да има предимство на виртуалната функция на своята пряка или непряка виртуален базов клас. Две различни класове могат да заменят виртуални функции различен виртуален базов клас. По този начин, множество производни класове могат да допринесат за изпълнението на интерфейса, който в един виртуален базов клас.
клас А

А () <> виртуална невалидни г (); виртуална невалидни з ();>; клас В1: виртуална публична A ; клас B2: виртуална публична A ; клас C: обществен B1, B2 обществен <>; невалидни основни ()

// функция Call В1 :: г // повикване функция В2 :: з

Ако два класа да заменят една и съща функция базов клас, които ги предизвикват, получени клас, не се замени тази функция е невалиден. В този случай, тя не може да се създаде таблица на виртуални функции, тъй като тази функция обаждане е двусмислен.






клас А

// функция C :: г замени функция В1 :: д, и В2 :: г // Добре - наричаме функция C :: г // неяснота - В1 :: з или В2 :: часа.

Много класове осигуряват просто и общи интерфейси трябва да се използва по няколко различни начина. Точната стойност на всяка функция интерфейс обект се определя, за която се нарича. Често между програмата, да издава заявка и предмет получаването им, е софтуерен слой. Теоретично междинната кодът не е необходимо да знае нищо за отделните сделки, в противен случай той би трябвало да бъдат променени при всяка промяна на набор от операции. Следователно такава междинна код трябва просто да мине по искане на получателя, някои от данните, представляващи операцията може да бъде ползвана.

Един лесен начин да се приложи този подход е да се изпрати на низ представителство на операцията, която трябва да бъде извикана. Въпреки това, тази линия някой трябва да се създаде и някой - декодиране да се определи какво операции тя отговаря. Това е доста трудно и неудобно. Това ще бъде възможно да се изпращат цели числа, съответстващи операции. Все пак, въпреки че броят и удобен за компютър, за хората от тяхната стойност не е очевидно. И все още се нуждаят от код, за да се определи това, което искате да се обадите.

C ++ осигурява средства за непреки препратки към член на клас. Указател към член на клас е стойност, която идентифицира член на класа. Можете да го третира като член на позицията на клас в класа на обекта, но, разбира се, компилаторът отчита разликите между данните на виртуални функции nonvirtual функции и т.н.

А указател към член на клас m се използва в комбинация с обекта. Оператори -> * и. * Оставя програмист да изрази следната последователност. р> * м m свързва към обекта посочи от стр. и OBJ. M * m свързва принадлежи OBJ на обект. Резултатът може да се използва в съответствие с типа м. Може да се запази в резултат на тези операции за бъдещото му използване.

Разбира се, ако знаехме какво е член на класа, в който искате да използвате, бихме могли да направим това директно, без да се използват указатели. Както и указатели към обичайните функции, указатели към членове на класа се използват, когато има нужда да се позова на един обект, чието име не е известно. Въпреки това, за разлика от указател към променлива или редовен функция в показалеца на член на класа е само указател към зоната на паметта. Това съответства повече или промяна в структурата на индекс в масива. Комбинацията от указател към член на класа с предмет или указател към обект дава който идентифицира даден член на даден обект.
клас Base действителен

Base () <>>; клас D1: обществен Base невалидни близо () нищожен печат () >; клас D2: обществен Base невалидни близо () нищожен печат () >;

typedef нищожен (Base :: * PF) (); невалидни основни () * PF1) (); (Pb -> * PF2) (); (Pb -> * pf3) ();>

// определи вида на указател към член функция на базовия клас // съхранява указател към член на клас // Base (отварят и затварят функции са виртуални, // и функция за печат - не-виртуална). // г - D1 клас обект // Call D1 функция :: отворен () // Обадете функцията D1 :: близо () // Функция повикване Base :: печат () // PB - указател към обект от клас Base (обект всъщност принадлежи клас D2) // Обадете се на функция D2 :: отворен () // Обадете функцията D2 :: близо () // извикване на функция Base :: печат ()

Shapes.h файл

Форми () статичен Int GetCount () вътр Left () конст вътр Top () конст вътр Right () конст Int дъно () конст виртуален невалидни Draw () = 0; виртуална невалидни движение (междинно съединение, където CONST форми * форма) = 0; виртуални форми * NewShape () = 0; виртуални форми * клонинг () = 0;>;

Shapes.cpp файл

#include "Shapes.h" INT Shapes :: брой = 0;

Storable.h файл

#define запаметяеми #include използване на пространството от имена STD; Приставка клас

Прибиращ (); виртуална Int прочетен () = 0; виртуална Int запис () = 0;>;

Storable.cpp файл

#include "Storable.h" Приставка :: Приставка (Конст Чар * f1, Конст Чар * f2) Прибиращ :: Прибиращ (конст * CHAR е, режим на междинно съединение) иначе, ако (режим == запис) > Приставка ::

Circle.h File *

#if. дефинирани (форми) #include "Shapes.h" # endif клас Circle: обществени фигури

Кръг () <> нищожен Draw (); нищожен Move (инт къде, на константи Shapes * форма);>;

Triangle.h File *

#if. дефинирани (форми) #include "Shapes.h" # endif клас триъгълник: обществени фигури

Триъгълник () <> нищожен Draw (); нищожен Move (инт къде, на константи Shapes * форма);>;

Circle_Storable.h файл

#include "Circle.h" #if. дефинирани (могат да се запишат) #include "Storable.h" # endif клас Circle_Storable: обществен кръг, виртуална публична Приставка Circle_Storable (конст * CHAR е, режим на междинно съединение, Int х = 0, Int у = 0, Int г = 0, Int С = 0): Прибиращ (е, режим), кръг (х, у, R, в) <>

Circle_Storable () <> вътр Read (); Int запис ();>;

Circle_Storable.cpp файл

Triangle_Storable.h файл

#include "Triangle.h" #if. дефинирани (могат да се запишат) #include "Storable.h" # endif клас Triangle_Storable: обществен триъгълник, виртуална публична Приставка Triangle_Storable (конст знак * е, режим на междинно съединение, Int x1 = 0, Int y1 = 0, Int х2 = 0, Int Y2 = 0, Int x3 = 0, Int Y3 = 0, Int С = 0): Прибиращ (е, режим), триъгълник (х1, у1, Х2, Y2, X3, Y3, в) <>

Triangle_Storable () <> вътр Read (); Int запис ();>;

Triangle_Storable.cpp файл

main.cpp файл

#include "Circle_Storable.h" #include "Triangle_Storable.h" невалидни основни () улова (конст * CHAR и) за (INT I = 0; и Равен (); за (INT I = 1; и Преместване (Фигури :: НАЛЯВО, форми [I - 1]); за (INT I = 0; и Равен (); // Масивът съхранява указатели към Фигури клас. Реални предмети принадлежат към класа или Circle_Storable Triangle_Storable. // който е клас, получени от класа форми. и от класа Приставка. Ние не знаем за какво точно класа // (Circle_Storable или Triangle_Storable) принадлежи към обекта, но може да конвертира указател към указател към класа Приставка. //, които, както и класа форми. Това е основата за двата класа. Все пак, това може да стане само по време на програмата за //, така че използвайте dynamic_cast оператор вид реализация. който проверява обекта принадлежи към клас от производни // форми и могат да се съхранят класове. и извършва превръщането. Ако обектът всъщност не принадлежи към класа // получен от тези класове, превръщането индекс на Shapes клас към указател към класа Приставка би било невъзможно, // и dynamic_cast оператор ще се върне стойността 0. за (INT I = 0; аз (Фигури [Ь]) -> Запис (); за (INT I = 0, п = форми :: GetCount (); и