Alkalmazottakat (Employee) tartunk nyilván egy polgármesteri hivatalnak készülő nyilvántartási rendszerünkben, amelyet a helyi kórház is használni fog. Az Alkalmazott a Személy osztályból (Person) származnak. A nyilvántartó rendszer két másik rendszerrel van kapcsolatban: az egyik az adóhivatal rendszere, a másik az egészségbiztosításé.
A Személy osztály deklarációja az alábbi:
class Person
{
protected:
string name;
int birthYear;
public:
Person(string name,
int birthYear):name(name), birthYear(birthYear){}
void print(){ cout << name << ' ' << birthYear << endl;}
void setBirthYear(int birthYear){ this->birthYear = birthYear; }
};
Az adóhivatal rendszere az alábbi osztályt adja, amibe nem nyúlhatunk bele, a forrása nincs meg, csak a .h file és a tárgykódú file valamilyen formátumban (.obj, .o, .a, .lib, .dll,.so):
class TaxSystem
{
unsigned tax;
public:
TaxSystem();
// Ezzel kell adót befizetni
void payTax(const ITaxPayer& taxPayer);
};
Ennek egy lehetséges implementációja az alábbi (a példa szerint nem áll rendelkezésre, csak binárisan, jelen példában nem akarjuk az összes operációs rendszerre lefordítva odaadni, inkább közöljük):
class TaxSystem
{
unsigned tax;
public:
TaxSystem():tax(0){};
// Ezzel kell adót befizetni
void payTax(const ITaxPayer& taxPayer)
{
// Húsz százalékot adózik
tax+=taxPayer.getIncome()*0.2-taxPayer.taxReduction();
}
};
Ennek az adófizetést végző függvénye az alábbi osztályt várja, amelyet mi is megkapunk:
class ITaxPayer
{
public:
// Az évi jövedelmet adja vissza
virtual unsigned getIncome()const=0;
// Az adókedvezményt adja vissza
virtual unsigned taxReduction()const=0;
};
Hasonlóan az egészségbiztosítás is rendelkezik egy rendszerrel, a függvények deklarációit .h állományban meg is kapjuk:
class HealthCare
{
public:
// Megnézi, van-e fedezet egy kezelésre
static bool isInsuranceForTreatment(IInsured& insured, unsigned amount);
// Levonja az kezelés költségét a biztosított egyenlegéből
static void chargeTreatment(IInsured& insured, unsigned amount);
};
Az implementáció nem áll rendelkezésre, csak binárisan, most az egyszerűség kedvéért megadjuk:
class HealthCare
{
public:
// Megnézi, van-e fedezet egy kezelésre
static bool isInsuranceForTreatment(IInsured& insured, unsigned amount)
{
if(insured.isValidInsurance() && insured.getInsuranceBalance() - amount >=0)
{
return true;
}
else
{
return false;
}
}
// Le vonja az kezelés költségét a biztosított egyenlegéből
static void chargeTreatment(IInsured& insured, unsigned amount)
{
if(isInsuranceForTreatment(insured,amount))
{
// Hibakezelés
assert(0);
}
else
{
insured.decreaseIsuranceBalance(amount);
}
}
};
Az IInsured osztály szintén rendelkezésre áll:
class IInsured
{
public:
// Az egészségbiztosítás egyenlegét adja vissz
virtual unsigned getInsuranceBalance()const=0;
// Megadja, hogy van-e az illetőnek érvényes biztosítása
virtual bool isValidInsurance()const=0;
//
virtual void decreaseIsuranceBalance(unsigned amount)=0;
};
Azt szeretnénk elérni, hogy az Employee osztály példányait egyszerűen tudjuk adóztatni, vagy ellenőrizni, van-e fedezet az ellátásra, illetve az ellátás költségét levonni a biztosításból.
Erre egy példa:
int main()
{
Employee emp ("James Bond", 1930,1952);
emp.salary=200000; // Ennyit keres havonta
emp.insuranceBalance+=700000; // Ennyi TB-t fizetnek utána, Mr. Bond gyakran kerül kórházba
// Az APEH rendszeréhez kapcsolódunk
TaxSystem ts;
// Adót fizetünk
ts.payTax(emp);
// Mr. Bond kórházba kerül egy lövöldözés után az Aranykéz utcában (Golden Hand c. epizód)
// Az OEP rendszeréhez kapcsolódik a kórház, megnézi, ki tudja-e fizetni a kezelést
if(!HealthCare::isInsuranceForTreatment(emp,500000))
{
cout << "No money for treatment" << endl;
}
// A kezelés után levonja a kezelés értékét a biztosításból
HealthCare::chargeTreatment(emp,500000);
}
Amennyiben több, általunk nem befolyásolható rendszerhez kell illeszkednünk, akkor gyakori a többszörös öröklés. Esetünkben szeretnénk, ha az Employee osztály példányait mind ITaxPayerként, mind IInsuredként használhatnánk. Vagyis ezekből is leszármaztatjuk:
class Employee: public Person, public ITaxPayer, public IInsured
{
int employmentYear;
public:
unsigned salary;
unsigned insuranceBalance;
Employee(string name, int birthYear,
int employmentYear):Person(name, birthYear),
employmentYear(employmentYear),salary(0), insuranceBalance(0){}
// Saját függvény
void setEmploymentYear(int employmentYear)
{
this->employmentYear = employmentYear;
}
// A Person virtuális tagfüggvényének felülírása
void print()
{
cout << name << ' ' << birthYear << ' '
<< employmentYear << endl;
}
// Az ITaxPayer virtuális tagfüggvényeinek
virtual unsigned getIncome()const
{
// 13. havi és egyéb dolgokat nem veszünk figyelembe
return salary*12;
}
// Ezt ki lehetne számolni a példa bonyolításával, ezt nem tesszük,
// a példában senkinek nem lesz adókedvezménye
unsigned taxReduction()const
{
return 0;
}
// Az IInsured virtuális tagfüggvényeinek felülírása
unsigned getInsuranceBalance()const
{
return insuranceBalance;
}
// Egy alkalmazott mindig biztosított
bool isValidInsurance()const
{
return true;
}
void decreaseIsuranceBalance(unsigned amount)
{
if(amount <= insuranceBalance)
{
insuranceBalance-=amount;
}
else
{
// Hibakezelés
assert(0);
}
}
};
Figyeljük meg, hogy implementációt csak a Person osztálytól örökölt, a többi esetben csak tisztán virtuális függvényeket implementált. A csak tisztán virtuális függvényeket tartalmazó osztály neve interfész (innen az I előtag). Vagyis csak egy osztálytól öröklünk implementációt, a többitől csak interfészt, amin keresztül a két másik rendszer hozzáférhet az objektum bizonyos tagfüggvényeihez. Ez követendő példa: maximum egy osztálytól örököljünk implelentációt, a többitől csak interfészt (azt is akkor, ha már kész, általunk nem módosítható komponenshez kell illesztenünk az osztályt)!