Міністерство науки і освіти України
Національний університет “Львівська політехніка”
Кафедра САПР
ЗВІТ
до лабораторної роботи № 4
Реалізація ієрархії в мові С++. Множинне успадкування.
з курсу " Методи та засоби об’єктно-орієнтованого проектування "
1. МЕТА РОБОТИ
Мета даної роботи є ознайомлення із принципами множинного успадкування.
2. ТЕОРЕТИЧНА ЧАСТИНА
Ієрархію простого успадкування можна описати, використовуючи структуру дерева, де кожен вузол - це підклас, який може породжувати довільну кількість додаткових підкласів. Як і у випадку простого успадкування, визначення private, protected i public в батьківському класі можна використовувати для управління доступом до екземплярів змінних і методів, які успадковані похідним класом (підкласом) від базового (батьківського) класу.
Крім того, специфікатори public - або private - похідного класу, як і при простому успадкуванні, визначають кожні класи, об’єкти яких мають прямий доступ до відкритих даних або функцій-членів базового класу.
Множинне успадкування реалізовано у версіях С++, починаючи з 2.0.
Підклас може успадковувати протокол одного або більше батьківських класів. При цьому, помимо специфікаторів public- і private- похідних класів використовується додаткова опція virtual.
Приклад опису класів при множинному успадкуванні:
class X1
{private:
d1;
m1;
protected
d2;
m2;
public:
d3;
m3;
};
class X2
{private:
d4;
m4;
protected
d5;
m5;
public:
d6;
m6;
};
class Z: public X1 , public X2
{private:
zd1;
zm1;
protected
zd2;
zm2;
private:
zd3;
zm3;
};
Похідний клас в ієрархії множинного успадкування не має доступу до захищених екземплярів змінних любих його базових класів.
При використанні множинного успадкування , в протокол похідного класу необхідно викликати конструктори базових класів для ініціалізації полів даних та ініціалізувати різні елементи об’єктів.
Порядок виклику конструкторів:
Ініціалізація здійснюється в порядку, визначеному ініціалізуючим списком з тим обмеженням, що конструктори базових класів завжди викликаються перед конструктором полів даних.
Void - конструктори базових класів, які явно не вказані в списку ініціалізації, викликаються після конструкторів, явно ініціалізованих базових класів, в цьому порядку, в якому вони йдуть в оголошенні класу. Але void - конструктори викликаються перед любим конструктором полів даних.
Для опису ієрархії множинного успадкування можна використати прямий ациклічний граф (ПАГ) (рис.1).
Parent
Child1 Child2
GrandChild
Рис.1. ПАГ множинного успадкування
В такому графі клас може з’явитись більше, ніж один раз. Розглянемо ПАГ множинного успадкування, представлений на рис.1. Елементи даних (екземпляри змінних) класу Parent з‘являються двічі в класі GrandChied. Перший набір успадковується через Chid1, другий через Chid2. Таке успадкування буває небажаним. Віртуальні базові класи [3,4,5] забезпечують механізм для уникнення дублювання елементів в класі, такому як GrandChied.
Індивідуальне завдання:
Із похідних класів, отриманих у лаб.роботі №3, шляхом множинного успадкування, утворити новий клас. Для об’єктів даного класу показати всі можливі механізми доступу до протоколів базових класів.
Текст програми:
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
//parent class "Integer"
class Integer
{
protected:
int value;
public:
//constructors
Integer():value(0){}
Integer(int v){value = v;}
//destructor
~Integer(){}
//methods
int getValue(){return value;}
void setValue(int v){value = v;}
//operators
//operator "=="
friend int operator == (const Integer& v1, const Integer& v2)
{ return (v1.value == v2.value); }
//operator "!="
friend int operator != (const Integer& v1, const Integer& v2)
{ return (v1.value != v2.value); }
//operator ">"
friend int operator > (const Integer& v1, const Integer& v2)
{ return (v1.value>v2.value); }
//operator "<"
friend int operator < (const Integer& v1, const Integer& v2)
{ return (v1.value<v2.value); }
//operator "+"
friend Integer operator + (const Integer& v1, const Integer& v2)
{ return Integer(v1.value+v2.value); }
//operator "-"
friend Integer operator - (const Integer& v1, const Integer& v2)
{ return Integer(v1.value - v2.value); }
//operator "*"
friend Integer operator * (const Integer& v1, const Integer& v2)
{ return Integer(v1.value * v2.value); }
//operator "/"
friend float operator / (const Integer& v1, const Integer& v2)
{
if(v2.value == 0) {cout<<"Division by zero!Stop"<<endl; return 0; }
return v1.value/(float)v2.value;;
}
//operator "<<"
friend ostream& operator << (ostream& stream, const Integer& v1)
{
stream<<(int)v1.value;
return stream;
}
//operator ">>"
friend istream& operator >> (istream& stream, const Integer& v1)
{
stream>>(int)v1.value;
return stream;
}
};
//child class "public Integer"
class pubInteger : public Integer
{
protected:
char* name;
void show()
{
cout<<"\n"<<name<<endl;
}
public:
pubInteger(): name("This is public child class"){}
pubInteger(int n): Integer(n),name("This is public child class"){}
friend class privInteger;
Integer operator ++ ()
{
show();
return Integer(++value);
}
};
//child class "private Integer"
class privInteger : private Integer
{
protected:
char* name;
void show()
{
cout<<"\n"<<name<<endl;
}
public:
privInteger(): name("This is private child class"){}
privInteger(int v): Integer(v), name("This is private child class"){}
int getValue(){return Integer::getValue();}
int compare(const pubInteger& p1)
{
return (value<p1.value?-1:(value==p1.value?0:1));
}
};
//child of multi parent class
class multiParent : public pubInteger, public privInteger
{
private:
char* name;
public:
multiParent():pubInteger(0){}
multiParent(int v):pubInteger(v){}
int getValue(){return pubInteger::getValue();}
void setValue(int v){pubInteger::setValue(v);}
};
void main(void)
{
clrscr();
multiParent i1;
multiParent i2(10);
privInteger i3(2);
pubInteger i4(1);
cout<<"multiParent#1 = "<<i1.getValue()<<endl
<<"multiParent#2 = "<<i2.getValue()<<endl
<<"privInteger#3 = "<<i3.getValue()<<endl
<<"pubInteger#4 = "<<i4<<endl
<<"Enter Integer#1: ";
int tmp;
cin>>tmp; i1.setValue(tmp);
cout<<"multiParent#1 = "<<i1.getValue()<<endl;
cout<<"++multiParent#1 = "<<(++i1)<<endl;
int cmp1 = i3.compare(i1);
int cmp2 = i2.compare(i4);
cout<<(cmp1==1?"\nprivInteger#3 is bigger then pubInteger#1":cmp1==0?"\nprivInteger#3 is equal to pubInteger#1":"\nprivInteger#3 is less then pubInteger#1");
cout<<(cmp2==1?"\nprivInteger#4 is bigger then pubInteger#2":cmp2==0?"\nprivInteger#4 is equal to pubInteger#2":"\nprivInteger#4 is less then pubInteger#2");
getch();
}
Результат роботи програми:
Висновок:
На даній лабораторній роботі я навчився і закріпив знання з роботою множинного успадкування, його особливості, поведінку батьківських методів та даних, які були оголошені, як private, protected, public.