Помогни ни да направим Uroci.net по - богат! Добави урок
Категории Други уроци Adobe Photoshop Adobe Illustrator Adobe Flash Adobe Fireworks DreamWeaver CSS и HTML Corel Draw Image Ready PHP SEO CMS Microsoft Windows Microsoft Word Microsoft Excel PowerPoint Microsoft Access Microsoft Publisher Linux Visual basic JavaScript Ajax 3ds Max Maya 3D C++
C++
Sound Forge Gimp SWiSH

C++ част.8 (Обектно-ориентирано)

C++ » C++
fix3d   трудност:    видян: 8028



Дефиниция на виртуален базов клас

Един базов клас се определя като виртуален чрез добавянето на клю-човата дума virtual към неговата декларация. Например, следващата декларация прави ZooAnimal виртуален базов клас на Bear и Raccoon.

// placement order of keywords public
// and virtual is not significant
class Bear : public virtual ZooAnimal { /* ... */ }
class Raccoon : virtual public ZooAnimal { /* ... */ }

Ако един виртуален базов клас дефинира конструктор, конструкторът не трябва да изисква списък от аргументи - това трябва да бъде конструктор без аргументи или конструктор, за който е определена стойност по премълчаване за всеки един от аргументите му. Освен това, няма нужда да бъде променяна дефиницията на ZooAnimal, за да се определи виртуалния базов клас. Ето дефиницията на ZooAnimal, с която ще работим, дискутирайки виртуалните базови класове: Това изискване вече е било премахвано веднъж от езика, макар че AT&T 2.0 версията на С++ го въвежда. Според сегашните правила, ако се изисква конструктор по подразбиране, но такъв няма, се предизвиква грешка по време на компилация. По-ранното ограничение е било въведено за да предпазва от грешка по време на компилация.

class ZooAnimal { // simplified definition
public:

ZooAnimal() { zooArea = 0; name = 0; }
ZooAnimal( char*, short );
void locate();
protected:
short zooArea;
char *name; };

По същия начин се използват обектите от класовете Bear и Raccoon. Един виртуален базов клас се инициализира както не виртуален базов клас:

Bear::Bear( char *nm ): ZooAnimal( nm, BEAR ) { ... }
Raccoon::Raccoon( char *nm )
: ZooAnimal( nm, RACCOON ) { ... }

Декларацията на Panda изглежда по същия начин както нейния не виртуален образец:

class Panda : public Bear, public Raccoon { ... };

Тъй като и Bear, и Raccoon декларират ZooAnimal като виртуален базов клас, всеки обект на Panda вече ще съдържа само един образец на ZooAnimal. Обикновено един извлечен клас може явно да инициализира само преките си базови класове. Например, в не виртуално извличане от ZooAnimal Panda може да не вика по име ZooAnimal в списъка за инициализация на конструктора си. Виртуалните базови класове са едно изключение. Ще обясним защо. Panda съдържа единствен образец на ZooAnimal, споделян от Raccoon и Bear. Raccoon и Bear, обаче, едновременно явно инициализират ZooAnimal. Образец на Panda не може да бъде инициализиран двукратно. Един виртуален базов клас се инициализира от класа, който е в действителност извличан. Например, не Raccoon или Bear, а Panda е в действителност извлечен от ZooAnimal. Panda може явно да инициализира ZooAnimal в списъка за инициализация на своя конструктор. Ако конструкторът на Panda не инициализира явно ZooAnimal, извиква се конструкторът по подразбиране на ZooAnimal. Никога не се прави инициализиране на ZooAnimal част в обект от типа Panda чрез Raccoon и Bear.

Конструкторът на Panda може да бъде дефиниран по следния начин:

Panda::Panda( char *nm ): ZooAnimal( nm, PANDA ),Bear( nm ), Raccoon( nm ) { ... }
Panda::Panda( char *nm ): Bear( nm ), Raccoon( nm ) { ... }

извиква конструктора по подразбиране на ZooAnimal.

Достъп до членовете на виртуален базов клас

Всеки обект от класовете Raccoon и Bear поддържа свое собствено множество от членове на ZooAnimal, което може да бъде достигнато точно по същия начин както унаследените членове от не виртуални извличания. При едно отделно преглеждане на програмния код не може да се направи разлика между употребата на обект на извличане от виртуален и на не виртуален базов клас; единствената разлика е в начина на отделянето на частта от обекта, съответна на базовия клас.

При не виртуално извличане всеки извлечен обект от класа съдържа долепващи се базова и извлечена част на класа (виж Фигура 7.4 ). Обект от класа Bear, например, има базова част ZooAnimal и Bear част. При виртуално извличане всеки обект от извлечения клас съдържа извлечена част и указател към частта, съответна на виртуалния базов клас. Виртуалният базов клас не се съдържа в обекта от извлечения клас. Това е илюстрирано за класовете Bear, Raccoon и Panda на Фигура 8.3.Един виртуален базов клас се подчинява на същите правила за public и private, както и при не виртуално извличане:

- унаследените членове при public виртуално извличане запазват нивото си на достъп - public или protected - в извлечения клас.
- унаследените членове при private виртуално извличане стават private членове на извлечения клас.

Какво става, когато еднократно-отдалечено извличане, такова като Panda, включва едновременно public и private образци на един виртуален базов клас? Например,

class ZooAnimal
{public:
void locate();
protected:
short zooArea;
};

class Bear :
public virtual ZooAnimal { /* ... */ };
class Raccoon :
private virtual ZooAnimal { /* ... */ };
class Panda :
public Bear, public Raccoon { /* ... */ };
class Raccoon : public virtual ZooAnimal
class Bear : public virtual ZooAnimal

Фигура 8.3 Представяне на виртуален базов клас

Panda наследява само едно копие на zooArea и locate(), защото ZooAnimal е виртуален базов клас. Въпросът е дали на Panda е разрешен достъпа до тези членове? При public онаследяване Panda има достъп до тези два члена на ZooAnimal. Обаче, те не са достъпни за Panda при private онаследяване. Кой вид онаследяване се взема в предвид при виртуално извличане? Вярно ли е следното обръщение?

Panda p;p.locate();

Да, обръщението е вярно. Взема се в предвид public онаследяването. Panda има достъп до zooArea и locate(). Като цяло, независимо от брояча образците на виртуалните базови класове в йерархията на онаследяването, ако съществува отделен public образец, един споделен образец при извличане се разглежда като public.

ZooAnimal дефинира член функция locate(), която Raccoon наследява. Обръщението

Bear b;

b.locate(); // Bear instance

вика образеца на Bear, a не този на ZooAnimal. При не виртуално извличане обръщението

Panda p;

p.locate(); // which locate? e двузначно, ако Panda не дефинира свой собствен образец на locate(). Ако обаче ZooAnimal е виртуален базов клас едновременно за Raccoon и Bear, се вика образеца locate() на Bear. Двузначността е премахната. При виртуално извличане се взема същинският извлечен образец на член функцията. Затова се взема образеца locate() на Bear, а не този на ZooAnimal, наследен в Raccoon.


Страници: «3 4 5 6 7 »

Регистрирайте се, за да добавите коментар

реклама

© Всички права запазени. 2006-2008. Created by: Site.bg
Препоръчваме: IT Новини | Кино и игри | Диплома.бг | Paparak.bg | Тунинг Портал | uchenik.com | TRAVEL туризъм | Реферати | AmAm.bg | Иде.ли | Курсови работи | AnimeS-bg.com | Фото Форум | Запознанства | Мрежа от приятели | IT Light | Spodeli.net | Фото-Култ | IDG.BG | Teenproblem.net | Блог - Образование | Fresh-BG.com | Hanovete.com | Bulfleet.com | Mythlands.com | Ohoboho.com | Казанлък.Com | News24 | Setcom.bg | Atol.bg | Elmaz.com | MobileBulgaria.com