Az öröklés egy kód-újrahasznosítási módszer, ahol az új osztályok a már
megírt osztályok alapján készülnek felhasználván azok tulajdonságait és
algoritmusait, átírván némely algoritmust és létrehozván pár új tulajdonságot
és algoritmust. Nem csak kódot, de időt is takarít meg, mert a már létező
osztályokat nem kell újra tesztelni. Adatokat és tagfüggvényeket örökölni egy
vagy több osztálytól is lehet. Mindhárom adattípust (public, private,
protected) lehet örökölni, de
legtöbbször a publikus öröklést használjuk. Ebben az esetben ugyanis a derivált
(örökölt) osztály objektumai bárhol használhatók az ősosztály objektumaiként
is. A fordított eset viszont nem igaz, azaz az ősosztály objektumai nem
objektumai a derivált osztálynak is. Tulajdonképpen ez a legalapvetőbb
különbség az osztályok kombinálása (amikor más osztályok objektumait használjuk
tagváltozóként) és az öröklés között. A derivált osztály objektumai az
ősosztály objektumaiként is kezelhetőek. Az angolban ezt „is a” (öröklés) és „has a” (kombináció) típusú osztály kapcsolatként emlegetik. Akár egy külső
függvény, a derivált osztály sem fér hozzá az ősosztályának privát tagjaihoz,
hacsak nincsenek ehhez hozzáférést nyújtó publikus vagy protected tagfüggvények
az ősosztályban. Az öröklés egyik fölösleges tulajdonsága, hogy örökölnek a nem
használt publikus tagfüggvények is. Ha az ősosztály valamely tagfüggvényének
működése nem felel meg a derivált osztálynak, akkor azt újra lehet deklarálni a
derivált osztályban. Az ősosztály friend függvényei nem öröklődnek. Az öröklésre
példa az Absztrakció című bejegyzésben található. 
1. Mutató típusú
objektumok átalakítása az osztályok között
     
A mutató típusú objektumokat az ősosztály és a derivált osztály között cast-tal lehet átalakítani vigyázva, hogy a
mutató és az új objektum típusa találjon.
point.h
#ifndef POINT_H
#define POINT_H
#include <iostream>
using std::ostream;
class Point
{
     friend ostream& operator<<(ostream&,
const Point&);
     public:
           Point(int = 0, int = 0); //konstruktor és a parametér hiányában fellépő értékek
           void setPoint(int, int); //Beállítja x és y protected tagváltozókat
           int getX() const { return x; }
           int getY() const { return y; }
     protected:                     //csak a derivált osztály érheti el
           int x, y;  //egy pont koordinátái
};
#endif
point.cpp
#include <iostream>
#include "point.h"
//konstruktor - beállítja a
tagváltozókat
Point::Point(int
a, int b) 
{ 
     setPoint(a,
b);
}
// a tagváltozók beállítása
void Point::setPoint(int
a, int b) 
{
     x =
a;
     y =
b;
}
// Kiírja az objektumot egyéni
formában
ostream& operator<<(ostream&
output, const Point& p)
{
     output
<< '[' << p.x << ", " << p.y << ']';
     return output; //fűzér mód
}
circle.h
#ifndef CIRCLE_H
#define CIRCLE_H
#include <iostream>
using std::ostream;
#include <iomanip>
using std::ios;
using std::setiosflags;
using std::setprecision;
#include "point.h"
class Circle : public
Point //A Point publikus deriváltja
{
     friend ostream& operator<<(ostream&,
const Circle&);
     public:
           Circle(double r = 0.0, int x
= 0, int y = 0);
           void setRadius(double);
           double getRadius() const;
           double area() const;
     protected:
           double radius;
};
#endif
circle.cpp
#include "circle.h"
// Előbb a Point konstruktorát hívja meg
Circle::Circle(double
r, int a, int
b) : Point(a, b)
{ 
     setRadius(r);
// és csak utána állítja be a saját tagváltozóit
}
void Circle::setRadius(double
r)
{ 
     radius
= (r > 0 ? r : 0); //a sugár csak pozitív lehet
}
double Circle::getRadius() const
{ 
     return radius; 
}
double Circle::area() const
{ 
     return 3.14159 * radius * radius; 
}
// Kiírja az objektumot egyéni
formában: Központ = [x, y]; Sugár = #.##
ostream& operator<<(ostream&
output, const Circle& c)
{
     output
<< "Központ = " << static_cast<Point>(c)<< ";";
     output
<< "Sugár = " <<
setiosflags(ios::fixed | ios::showpoint)
                                 << setprecision(2) << c.radius;
     return output;
}
test_point_circle.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
#include "circle.h"
int main()
{
     Point
*pointPtr = 0, p(30, 50);
     Circle
*circlePtr = 0, c(2.7, 120, 89);
     cout
<< "A p pont: " << p
<< endl;
     cout
<< "A c kör: " << c
<< endl;
     //a Circle objektum címét egy Point típusó mutatóba írja
     pointPtr
= &c; //upcasting
     cout
<< "\nA c kör a Point osztály
szemszögébôl: " << *pointPtr << endl;
     //A Circle mutató felveszi a Point mutató értékét, ami
Circle objektumra mutat
     circlePtr
= static_cast<Circle*>(pointPtr); //downcasting
     cout
<< "\nA c kör a Circle osztály
szemszögébôl:\n" << *circlePtr << endl;
     //területszámítás
     cout
<< "A c kör területe:
circlePtr->area() = " << circlePtr->area() <<
endl;
     //a Point objektum címét egy Point típusó mutatóba írjuk
     pointPtr
= &p;
     //A
Circle mutató felveszi a Point mutató értékét, ami Point objektumra mutat
     circlePtr
= static_cast<Circle*>(pointPtr);
     cout
<< "\nA p pont a Circle osztály
szemszögébôl:\n" << *circlePtr << endl;
     //teruletszámítás
     cout
<< "A c kör területe:
circlePtr->area() = " << circlePtr->area() <<
endl;
     return 0;
}
A kimenet:
A p pont: [30,
50]
A c kör: Központ
= [120, 89];Sugár = 2.70
A c kör a Point
osztály szemszögébôl: [120, 89]
A c kor a Circle
osztály szemszögébôl:
Központ = [120,
89];Sugár = 2.70
A c kör
területe: circlePtr->area() = 22.90
A p pont a
Circle osztály szemszögébôl:
Központ = [30,
50];Sugár = 0.00
A c kör
területe: circlePtr->area() = 0.00
A Point ősosztály publikus interfésze tartalmazza a setPoint, getX és getY tagfüggvényeket. Az x és y tagváltozók viszont protected típusúak, hogy az osztály közvetlen felhasználói ne férjenek hozzá, de a
derivált osztályok igen. Ha private típusúak lennének, akkor a derivált osztály is csak a Point publikus függvényeivel érhetné el. A Circle osztály a Point ősosztály publikus deriváltja: class Circle : public Point. Ez azt jelenti, hogy a Point
minden public és protected tagja átöröklődött a Circle osztályba. Azt is jelenti, hogy a Circle publikus interfésze nem csak az area, setRadius és getRadius tagfüggvényekből áll, hanem magába foglalja a Point ősosztály publikus tagfüggvényeit is. Az
öröklésnél fontos, hogy a konstruktorok a megfelelő sorrendben hívódjanak meg.
Előbb az ős és utána az utód tagváltozóit kell inicializálni. Legegyszerűbb a
paraméterlista után kettősponttal jelezni, hogy a paraméterek közül melyek
inicializálják a Pointer osztály tagváltozóit: Circle::Circle(double
r, int a, int
b) : Point(a, b). Ebben az
esetben az a és a b lesz amit a Point konstruktor megkap. Ha ezt nem írjuk oda,
akkor is a Point konstruktor fut le hamarább, csakhogy az inicializált értékekkel,
melyek ebben az esetben nullák: Point(int = 0, int = 0) . Ha ez az inicializálás sincs megírva, akkor a fordító hibát jelez. A Point *pointPtr = 0, p(30,
50); programkód létrehoz egy NULL
mutatót és egy p objektumot. Ugyanígy
készül a Circle objektum is.
Mindét osztálynak van egy operátorfüggvénye, ami túlterheli a << operátort és saját stílusban írja ki az
objektumokat. A Circle
derivált osztály használhatja a Point
ősosztály operátorfüggvényét is, ám az csak a saját maga által ismert adatokat
tudja kiírni. Hogy a Point
operátorfüggvénye hívódjon meg, Point
típusú mutatót kell kiíratni, tehát a pointPtr fel kell vegye a Circle típusú objektum címét. A pointPtr = &c; műveletet upcasting-nak nevezik, mert a
derivált objektumot kezeljük ősobjektumként. Ez azt jelenti, hogy csak azok az
adatok elérhetőek az objektumból amelyek az ősosztályból valók, ebben az
esetben az x és y koordináta. Ennek ellenkezője a
downcasting: circlePtr
= static_cast<Circle*>(pointPtr);. Az upcasting esetén a Circle objektum mutatója Point típusú lett. A downcasting esetén visszaalakítás
történik, melyben az értéket csakis egy Circle
típusú mutató veheti fel. A program végül megadja a Point objektum címét a pointPtr mutatónak, majd átalakítja Circle mutatóvá. Ennek eredménye, hogy kiíráskor
a Circle operátorfüggvénye fog meghívódni és nem
fogja tudni, hogy mennyi a Point
objektum területe és sugara, ezért az inicializált nullákkal helyettesíti az
ismeretlen adatokat.
     
Annak ellenére, hogy a derivált objektum az ősosztályból származik,
típusa mégis különbözhet. A publikus öröklés esetén a derivált objektumokat
lehet ősi objektumként kezelni, hiszen a tagok hozzáférési típusa nem változik.
Az öröklés célja, hogy az alaptulajdonságok mellett új tulajdonságokat
soroljunk fel, ezért a derivált osztály mindig több taggal rendelkezik mint az
ősosztály. Az ősosztályban ezért is nem lehet a derivált objektumokra
hivatkozni, mert az ismeretlen tagok definiálatlanul maradnának. A publikus
öröklés lehetővé teszi, hogy a derivált osztály mutatója átalakítható legyen,
hogy az ősosztály objektumára mutasson, ahogyan ezt a fenti példában láttuk. Tulajdonképpen
négyféleképp kombinálhatóak a mutatók és az objektumok a derivált és az
ősosztály között:
1. Az
ősobjektumra való hivatkozás egy ősmutató segítségével
pointPtr = &p;
      2. A
derivált objektumra való hivatkozás egy derivált mutató segítségével
circlePtr = &c;
      3. A
derivált objektumra való hivatkozás egy ősmutató segítségével. Ez lehetséges,
hiszen a derivált objektum az ősosztály objektuma is, viszont csak az ősosztály
tagjait használhatjuk, különben a fordító hibát jelez.
     pointPtr = &c;
4. Az
ősobjektumra való hivatkozás egy derivált mutató segítségével. Közvetlenül nem
lehet, csak ha átalakítjuk a derivált mutatót ősmutatóvá.
     circlePtr
= static_cast<Circle*>(pointPtr);
2. Tagfüggvények
használata
     
A derivált és az ősosztályok tagfüggvényei között olykor csak kevés
eltérés van, mint például az előző példában szereplő operátorfüggvények esetén.
Ilyenkor nem érdemes a függvény nevét megváltoztatni, ugyanis felülírható az
ősosztály tagfüggvénye. Egyszerűen újra kell deklarálni az adott függvényt a
derivált osztályba, és onnantól az lesz az elsődlegesen érvényes függvény.
Továbbra is használható marad az ősosztály tagfüggvénye, ám használni kell a
tartományoperátort.
employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
class Employee
{
     public:
           Employee(const char*, const char*);
           void print() const;  // Kiírja a vezeték- és keresztnevet
           ~Employee();
     private:
           char* firstName;//dinamikusan
lefoglalt string
           char* lastName; //dinamikusan
lefoglalt string
};
#endif
employee.cpp
#include <iostream>
using std::cout;
#include <cstring>
#include <cassert>
#include "employee.h"
Employee::Employee(const
char* first, const
char* last)
{
     firstName
= new char[strlen(first)
+ 1]; // dinamikus memórialefoglalás
     assert(firstName
!= 0);                  //
abort ha nem sikerül lefoglalni
     strcpy(firstName,
first);                //
bemásolja a bejövő paramétert a tagváltozóba
     lastName
= new char[strlen(last)
+ 1];
     assert(lastName
!= 0);
     strcpy(lastName,
last);
}
void Employee::print() const
{ 
     cout
<< firstName << ' ' <<
lastName; 
}
Employee::~Employee()
{
     delete[] firstName; //memória
felszabaditás
     delete[] lastName; 
//memória felszabaditás
}
hourly.h
#ifndef HOURLY_H
#define HOURLY_H
#include "employee.h"
class HourlyWorker : public
Employee
{
     public:
           HourlyWorker(const char*,const char*,double, double);
           double getPay() const;
           void print() const; //az ososztály tagfüggvényének felülírása
     private:
           double wage;
           double hours;
};
#endif
hourly.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::ios;
using std::setiosflags;
using std::setprecision;
#include "hourly.h"
HourlyWorker::HourlyWorker(const char* first, const char* last, 
   double initHours, double
initWage) : Employee(first, last)
{
     hours
= initHours;
     wage
= initWage;
}
//A munkások fizetése
double HourlyWorker::getPay() const
{ 
     return wage*hours; 
}
//A felülírt függvény: kiírja a
fizetéseket is
void HourlyWorker::print() const
{
     cout
<< "HourlyWorker::print():"
<< endl;
     Employee::print();
//az eredeti függvény
     cout
<< " egy munkás ember havi "
     <<
setiosflags(ios::fixed | ios::showpoint)
     <<
setprecision(2) << getPay() << "
EUR minimálbérrel." << endl;
}
test_hourlyworker.cpp
#include"hourly.h"
int main()
{
     HourlyWorker
h("Bob", "Smith",
40.0, 10.00);
     h.print();
     return 0;
}
A kimenet:
HourlyWorker::print():
Bob Smith egy
munkás ember havi 400.00 EUR minimálbérrel.
     
Az Employee osztály
definíciója két char* privát tagváltozóból és három
tagfüggvényből áll. A konstruktor két karakterláncot kap paraméternek,
melyeknek dinamikusan lefoglal egy-egy char táblát a memóriában. Ha a helylefoglalás sikertelen, az assert hibaüzenettel lépik ki a programból.
Használható a try/catch szekvencia is,
mely bad_alloc kivételt
generál ha a new nem működött
megfelelően. Mivel az Employee osztály tagváltozói (vagy adattagjai) privátak, az egyetlen módszer az
elérésükhöz a print függvény, amely
kiírja őket. Az osztály destruktora felszabadítja a tagváltozóknak dinamikusan
lefoglalt memóriát elkerülve ezzel a memory leak nevű jelenséget.
     
Az HourlyWorker osztály az Employee osztályból van származtatva publikus
típusú örökléssel. Felülírja a print az ősosztályban is létező print függvényt, így két print függvényhez van hozzáférése. Ilyen
esetben általában a derivált változat alkalmazza az ősi változatot is, hogy
kiírja az ott elérhető információkat, ehhez azonban eléje kell írja az
ősosztály nevét: Employee::print();
3. A public, protected
és private típusú tagok öröklődése
     
Az osztályok származtatásakor az ősosztályt lehet public, private vagy protected típusú örökléssel származtatni. A private és protected nagyon ritka, inkább a public típust használjuk. A következő
táblázatban fel van sorolva mindenik hozzáférési típusú származtatás és hogy
mihez ad hozzáférést az ősosztályból.
Az ősosztály tagjainak hozzáférési
  típusa, amelyet a derivált osztály elérhet 
 | 
  
Öröklés típusa 
 | 
 ||
public 
 | 
  
protected 
 | 
  
private 
 | 
 |
public 
 | 
  
Az ősosztály public tagjai public hozzáférésűek a derivált osztályban is. Közvetlenül
  elérhetőek bármilyen nem statikus tagfüggvénnyel vagy osztályon kívüli friend
  függvénnyel. 
 | 
  
Az ősosztály public tagjai protected hozzáférésűek a derivált osztályban. Közvetlenül
  elérhetőek bármilyen nem statikus tagfüggvénnyel vagy osztályon kívüli friend
  függvénnyel. 
 | 
  
Az ősosztály public tagjai private hozzáférésűek a derivált osztályban. Közvetlenül
  elérhetőek bármilyen nem statikus tagfüggvénnyel vagy osztályon kívüli friend
  függvénnyel. 
 | 
 
protected 
 | 
  
Az ősosztály protected tagjai protected hozzáférésűek a derivált osztályban is. Közvetlenül
  elérhetőek bármilyen nem statikus tagfüggvénnyel vagy osztályon kívüli friend
  függvénnyel. 
 | 
  
Az ősosztály protected tagjai protected hozzáférésűek a derivált osztályban is. Közvetlenül
  elérhetőek bármilyen nem statikus tagfüggvénnyel vagy osztályon kívüli friend
  függvénnyel. 
 | 
  
Az ősosztály protected tagjai private hozzáférésűek a derivált osztályban. Közvetlenül
  elérhetőek bármilyen nem statikus tagfüggvénnyel vagy osztályon kívüli friend
  függvénnyel. 
 | 
 
private 
 | 
  
Az ősosztály private tagjai nem elérhetőek a derivált
  osztályban. Közvetlenül elérhetőek bármilyen nem statikus tagfüggvénnyel vagy
  osztályon kívüli friend függvénnyel, ha az eléréshez az ősosztály függvényeit
  használjuk. 
 | 
  
Az ősosztály private tagjai nem elérhetőek a derivált
  osztályban. Közvetlenül elérhetőek bármilyen nem statikus tagfüggvénnyel vagy
  osztályon kívüli friend függvénnyel, ha az eléréshez az ősosztály függvényeit
  használjuk. 
 | 
  
Az ősosztály private tagjai nem elérhetőek a derivált
  osztályban. Közvetlenül elérhetőek bármilyen nem statikus tagfüggvénnyel vagy
  osztályon kívüli friend függvénnyel, ha az eléréshez az ősosztály függvényeit
  használjuk. 
 | 
 
Látható, hogy a public típusú öröklésnél minden public  tag public marad, a protected pedig protected a származtatott osztályban is. A protected öröklés mindent protected típussá tesz, a private öröklés pedig mindent private típussá. Ez utóbbival az a baj, hogy minden tagfüggvény az ősosztályból
segédfüggvénnyé válik a derivált osztályban. Egyik típusú öröklés sem enged
hozzáférést az ősosztály private hozzáférésű tagjaihoz. Ha a
derivált osztályból is deriválunk osztályokat, akkor nem kell a legősibb
osztályig felsorolni mindent, csupán azt az osztályt ami egy absztrakciós
szinttel felette van. Ebben az esetben a legősibb osztály közvetett őse a
derivált osztálynak.
4. A derivált osztályok
konstruktorai és a destruktorai
     
A derivált osztály objektumai létrehozásakor az ősosztály konstruktorai
futnak le előbb. Ezek és az operátorfüggvények nem öröklődnek át, viszont
használhatóak a derivált osztály konstruktoraiban és operátor függvényeiben. A
destruktorok fordított sorrendben hívódnak meg, azaz előbb a derivált osztály
objektumai bomlanak le, aztán az ősosztály objektumai.
     
Tegyük fel, hogy az ősosztály és a derivált osztály is egy másik, „idegen”
osztály objektumait tartalmazza. Amikor létrehozunk egy objektumot a derivált
osztályban, először az ősosztályban lévő „idegen” objektumok konstruktora
hívódik meg, majd az ősosztály konstruktora, majd a derivált osztályban lévő
„idegen” objektumok konstruktora, végül a derivált osztály konstruktora. A
destruktorok fordított sorrendben futnak le.
point2.h
#ifndef POINT2_H
#define POINT2_H
class Point
{
     public:
           Point(int = 0, int = 0);
           ~Point();
     protected: //csak a
derivált osztály látja
           int x, y;
};
#endif
point2.cpp
#include <iostream>
using std::cout;
using std::endl;
#include "point2.h"
Point::Point(int
a, int b)
{
     x =
a;
     y =
b;
     cout
<< "Point konstruktor: "
            << '['
<< x << ", " <<
y << ']' << endl;
}
Point::~Point()
{
     cout
<< "Point destruktor: "
            << '['
<< x << ", " <<
y << ']' << endl;
}
circle2.h
#ifndef CIRCLE2_H
#define CIRCLE2_H
#include "point2.h"
class Circle : public
Point
{
     public:
           Circle(double r = 0.0, int x
= 0, int y = 0);
           ~Circle();
     protected:
           double radius;
};
#endif
circle2.cpp
#include <iostream>
using std::cout;
using std::endl;
#include "circle2.h"
Circle::Circle(double
r, int a, int
b) : Point(a, b)
{
     radius
= r;
     cout
<< "Circle konstruktor: a sugár: "
            << radius << " [" << x << ", " << y << ']' << endl;
}
Circle::~Circle()
{
     cout
<< " Circle
destruktor: a sugár: "
            << radius << " [" << x << ", " << y << ']' << endl;
}
test_point2_circle2.cpp
#include <iostream>
using std::cout;
using std::endl;
#include "circle2.h"
int main()
{
     //Konstruktor és destruktor teszt
     {
           Point
p(11, 22);
     }
     cout
<< endl;
     Circle
circle1(4.5, 72, 29);
     cout
<< endl;
     Circle
circle2(10, 5, 5);
     cout
<< endl;
     return 0;
}
A kimenet:
Point
konstruktor: [11, 22]
Point
destruktor: [11, 22]
Point
konstruktor: [72, 29]
Circle
konstruktor: a sugár: 4.5 [72, 29]
Point
konstruktor: [5, 5]
Circle
konstruktor: a sugár: 10 [5, 5]
Circle
destructor: a sugár: 10 [5, 5]
Point
destruktor: [5, 5]
Circle
destructor: a sugár: 4.5 [72, 29]
Point
destruktor: [72, 29]
A Circle osztály a Point publikus derivált osztálya, melynek van egy radius tagváltozója az örökölt tagváltozók
mellett. A Circle konstruktora
meghívja a Point konstruktorát, hogy
inicializálja az ősosztály x és y tagváltozóit. A főprogramban a p objektum külön blokkban van deklarálva,
így amikor a blokk végére ér, meghívódik a Point destruktora. Ezek után a circle1 és circle2 objektumok következnek, melyeknél látható, hogy
előbb a Point konstruktora fut
le.
5. A „uses a” és a „knows
a” típusú kapcsolat
    
 Az osztályok öröklése és a
kombinálása a kód-újrahasznosítást szorgalmazza olyan osztályok révén, melyeknek
közös tagjaik vannak. Ahogyan egy „személy” típusú objektum nem „jármű” típusú
objektum ugyanúgy nem is lehet annak leszármazottja vagy őse sem. A „személy”
objektumnak viszont használhat egy (uses
a) „jármű” objektumot. Egy objektum egy mutatóval, referenciával vagy közvetlen
módon használhat egy másik objektumot és annak nem-privát tagfüggvényeit. Egy
objektum tudhat egy (knows a) másik
objektum létezéséről, azaz tartalmazhat egy mutatót vagy referenciát egy másik
objektumra. A különbség a „használ” és „tud róla” között, hogy míg a „használ”
esetben mindkét objektum létezése azonos időtartamú, addig a „tud róla” esetben
az objektumok egymástól függetlenül is létezhetnek. A következő példában a Cylinder és a Circle osztályok a Point osztályból származnak közvetetten és
közvetlenül.
point.h
#ifndef POINT_H
#define POINT_H
#include <iostream>
using std::ostream;
class Point
{
     friend ostream& operator<<(ostream&,
const Point&);
     public:
           Point(int = 0, int = 0);
           void setPoint(int, int); 
           int getX() const { return x; } 
           int getY() const { return y; } 
     protected:
           int x, y; 
};
#endif
point.cpp
#include <iostream>
#include "point.h"
Point::Point(int
a, int b)
{ 
     setPoint(a,
b); 
}
void Point::setPoint(int
a, int b)
{
     x =
a;
     y =
b;
}
ostream& operator<<(ostream&
output, const Point& p)
{
     output
<< '[' << p.x << ", " << p.y << ']';
     return output; //fűzér mód
}
circle.h
#ifndef CIRCLE_H
#define CIRCLE_H
#include <iostream>
using std::ostream;
#include <iomanip>
using std::ios;
using std::setiosflags;
using std::setprecision;
#include "point.h"
class Circle : public
Point
{
     friend ostream& operator<<(ostream&,
const Circle&);
     public:
           Circle(double r = 0.0, int x
= 0, int y = 0);
           void setRadius(double);
           double getRadius() const;
           double area() const;
     protected:
           double radius;
};
#endif
circle.cpp
#include "circle.h"
Circle::Circle(double
r, int a, int
b) : Point(a, b)
{ 
     setRadius(r);
}
void Circle::setRadius(double
r)
{ 
     radius
= (r > 0 ? r : 0); 
}
double Circle::getRadius() const
{ 
     return radius; 
}
double Circle::area() const
{ 
     return 3.14159 * radius * radius; 
}
ostream& operator<<(ostream&
output, const Circle& c)
{
     output
<< "A kör közepe = "
<< static_cast<Point>(c)
              << "\nA
kör suagara = "
              << setiosflags(ios::fixed |
ios::showpoint)
              << setprecision(2) << c.radius;
     return output; //fűzér mód
}
cylinder.h
#ifndef CYLINDER_H
#define CYLINDER_H
#include <iostream>
using std::ostream;
#include "circle.h"
class Cylinder : public
Circle
{
     friend ostream& operator<<(ostream&,
const Cylinder&);
     public:
           Cylinder(double h = 0.0, double
r = 0.0,
           int x = 0, int y =
0);
           void setHeight(double);
           double getHeight() const;
           double area() const;
           double volume() const;
     protected:
           double height;
};
#endif
cylinder.cpp
#include "cylinder.h"
Cylinder::Cylinder(double
h, double r, int
x, int y) : Circle(r, x, y)
{ 
     setHeight(h);
}
void Cylinder::setHeight(double
h)
{ 
     height
= (h >= 0 ? h : 0); 
}
double Cylinder::getHeight() const
{ 
     return height; 
}
double Cylinder::area() const
{
     return 2 * Circle::area() +
     2 *
3.14159 * radius * height;
}
double Cylinder::volume() const
{ 
     return Circle::area() * height; 
}
ostream& operator<<(ostream&
output, const Cylinder& c)
{
     output
<< static_cast<Circle>(c)
              << "\nA
henger magassága = " << c.height;
     return output; //fűzér mód
}
test_cylinder.cpp
#include<iostream>
using std::cout;
using std::endl;
#include "cylinder.h"
int main()
{
     Cylinder
cyl(5.7, 2.5, 12, 23);
     cout
<< "x = " <<
cyl.getX()      //
A Point interfészből
            << "\ny
= " << cyl.getY()  // A Point interfészből
            << "\nsugár
= " << cyl.getRadius() //A Circle
interfészből
            << "\nmagasság
= " << cyl.getHeight() << "\n\n";
// A sajat interfészből
     cyl.setHeight(10);   // A saját
interfészből
     cyl.setRadius(4.25); // A Circle
interfészből
     cyl.setPoint(2,
2);  // A Point
interfészből
     cout
<< "cyl:\n" << cyl
<< '\n';
     cout
<< "A henger területe: "
<< cyl.area() << '\n'; // A saját interfészből
     Point&
pRef = cyl;
     cout
<< "\nA cyl a Point osztály
szemszögéből: " << pRef << "\n\n";
     Circle&
circleRef = cyl;
     cout
<< "A cyl a Circle osztály
szemszögéből:\n" << circleRef << '\n';
     cout
<< "A henger területe: "
<< circleRef.area() << endl;
     return 0;
}
A kimenet:
x = 12
y = 23
sugár = 2.5
magasság = 5.7
cyl:
A kör közepe =
[2, 2]
A kör suagara =
4.25
A henger
magassága = 10.00
A henger
területe: 380.53
A cyl a Point
osztály szemszügéből: [2, 2]
A cyl a Circle
osztály szemszögéből:
A kör közepe =
[2, 2]
A kör suagara =
4.25
A kör területe:
56.74
A Cylinder  osztály a Circle osztály deriváltja, amely a Point osztály deriváltja. Ez azt jelenti, hogy
a Point és a Cyrcle interfésze elérhető a Cylinder osztályban, amely még hozzáteszi a setHeight, getHeight, volume
és area tagfüggvényeket.
Ezek közül az area megtalálható a Circle osztályban is, azonban felülíródik. A Cylinder konstruktora meg kell hívja a Circle konstruktorát. A Point konstruktorát a Circle konstruktora hívja meg. A derivált
osztály konstruktora csak a közvetlen ősosztály konstruktorának meghívásáért
felelős. A főprogramban a cyl egy
Cylinder típusú objektum, melyre az összes létező
interfészt alkalmazva van. Ezután deklarálva van egy Point típusú referencia, mely a cyl objektumra hivatkozik: Point& pRef = cyl;. A pRef így
az objektumból csak a Point
tudásának eleget tevő koordinátákat látja. Hasonló a helyzet a Circle& circleRef = cyl; esetben is, ahol a circleRef referencia csak a Circle által ismert adatokat tudja kiírni. Ebben
az esetben az area az eredeti és nem a
felülírt függvényt fogja jelenti. A szemszögek kiírásához ugyanilyen módon jó
lett volna egy print() függvény is, azonban az << operátor átdefiniálása olvashatóbbá teszi a kódot.
6. A többszörös öröklés
    
 A derivált osztálynak több
ősosztálya is lehet. A következő példában a Derived osztály a Base1 és a Base2 osztályok leszármazottja.
base1.h
#ifndef BASE1_H
#define BASE1_H
class Base1
{
     public:
           Base1(int x){ value = x; }
           int getData() const {
return value; }
     protected:
           int value;
};
#endif
base2.h
#ifndef BASE2_H
#define BASE2_H
class Base2
{
     public:
           Base2(char c){ letter = c; }
           char getData() const
{ return letter; }
     protected: 
           char letter;
};
#endif
derived.h
#ifndef DERIVED_H
#define DERIVED_H
#include <iostream>
using std::ostream;
#include "base1.h"
#include "base2.h"
class Derived : public
Base1, public Base2
{
     friend ostream& operator<<(ostream
&, const Derived&);
     public:
           Derived(int, char, double);
           double getReal() const;
     private:
           double real;
};
#endif
derived.cpp
#include "derived.h"
Derived::Derived(int
i, char c, double
f) : Base1(i), Base2(c), real(f)
{}//az f paramétert a
real privát tagváltozóba teszi
double Derived::getReal() const
{ 
     return real;
}
ostream& operator<<(ostream&
output, const Derived& d)
{
     output
<< "value = " <<
d.value        //A Base1-ből
              << "\nletter
= " << d.letter  //A Base2-ből
              << "\nreal
= " << d.real;     //A sajátból
     return output;
}
test_derived.cpp
#include <iostream>
using std::cout;
using std::endl;
#include "derived.h"
int main()
{
     Base1
b1(10), *base1Ptr = 0;
     Base2
b2('Z'), *base2Ptr = 0;
     Derived
d(7, 'A', 3.5);
     cout
<< "b1 tartalma: " <<
b1.getData()
            << "\nb2
tartalma: " << b2.getData()
            << "\nd
tartalma:\n" << d << "\n\n";
     cout
<< "A Derived tagjai egyenként is
elérhetőek:"
            << "\nvalue:
" << d.Base1::getData()
            << "\nletter:
" << d.Base2::getData()
            << "\nreal:
" << d.getReal() << "\n\n";
     cout
<< "d mint az ősosztályok
objektuma:\n";
     base1Ptr
= &d; // A Base1 objektuma
     cout
<< "base1Ptr->getData() = "
<< base1Ptr->getData() << '\n';
     base2Ptr
= &d; // A Base2 objektuma
     cout
<< "base2Ptr->getData() = "
<< base2Ptr->getData() << '\n';
     return 0;
}
A kimenet:
b1 tartalma: 10
b2 tartalma: Z
d tartalma:
value = 7
letter = A
real = 3.5
A Derived tagjai egyenként
is elérhetőek:
value: 7
letter: A
real: 3.5
d mint az ősosztályok
objektuma:
base1Ptr->getData() = 7
base2Ptr->getData() = A
A többszörös öröklés az ősosztályok
felsorolása révén valósul meg: class Derived : public Base1, public Base2. A derivált osztály konstruktorában mindenik ősosztály konstruktorát meg kell
hívni, hogy inicializálódjanak az onnan örökölt értékek is. A főprogram
mindenik osztálytípusból deklarál egy-egy objektumot, majd kiírja ezek
tartalmát a beépített tagfüggvények és az operátorfüggvény segítségével. A
tagfüggvények nevei nem téveszthetők össze, hisz más-más objektumhoz tartoznak.
Amikor egyenként vannak kiírva, akkor is ott áll az adatok előtt az
osztályazonosító (pl. d.Base1::getData()). Ha
egyedi nevük lenne, nem lenne szükség osztályazonosítóra. Végül pedig két
upcasting látható az ősosztályokra, valamint a mutatók alkalmazása a függvények
megkülönböztetésére.