Štrukturované typy

Štruktúry

#include "stdio.h"
#include "string.h"

struct{int a;char b;}temp1,temp2={2,'f'};

struct Clovek{
char meno[20];
char priezvisko[20];
int vek;
int vaha;
int vyska;

void ShowClovek(){
printf("\n------------");
printf("\nMeno:        %s",this->meno);
printf("\nPriezvisko:  %s",this->priezvisko);
printf("\nVek:         %d",this->vek);
printf("\nVyska/Vaha:  %d/%d",this->vyska, this->vaha);
}

void InitClovek();


}temp;

void Clovek::InitClovek(){
strcpy(meno,"");strcpy(priezvisko,"");
vek=0;vaha=0;vyska=0;}


void InitClovek2(Clovek *Vstup){
strcpy(Vstup->meno,"n/a");strcpy(Vstup->priezvisko,"n/a");
Vstup->vek=50;Vstup->vaha=50;Vstup->vyska=170;
}

int main(int argc, char* argv[])
{
Clovek *Otec = new Clovek;
int Clovek;             //prekrytie nazvu
struct Clovek Matka;    //pristup k typu cez plne meno

strcpy(Otec->meno,"Anton");
strcpy(Otec->priezvisko,"Novy");
Otec->vek=34;
Otec->vaha=82;
Otec->vyska=182;

strcpy(Matka.meno,"Maria");
strcpy(Matka.priezvisko,"Nova");
Matka.vek=32;
Matka.vaha=58;
Matka.vyska=177;

Otec->ShowClovek();
Matka.ShowClovek();

Otec->InitClovek();Otec->ShowClovek();
Matka.InitClovek();Matka.ShowClovek();
InitClovek2(Otec);Otec->ShowClovek();
InitClovek2(&Matka);Matka.ShowClovek();

temp.ShowClovek();

temp=Matka;
temp.ShowClovek();

char pause=getchar();

        return 0;
}
Štruktúra definuje nový typ objektu, v ktorom sú jednotlivé menšie objekty. Objektami môžu byť nielen premenné, ale aj funkcie (tie sa potom nazývajú členské funkcie), ďalšie štruktúry alebo triedy, typy enum a bitové polia. Členské objekty nemôžu byť register, auto, ani extern, ale môžu byť static (to má špeciálny význam). Štruktúra nemôže obsahovať člen typu samej seba, ale môže obsahovať smerník na takýto objekt.
V programe potom môžem zadeklarovať premenné tohto novovytvoreného typu. Dá sa to spraviť buď za deklaráciou štruktúry (premenná temp), alebo (krajšie a prehľadnejšie) pomocou MenoStruktury NovaPremenna;
Pomocou deklarácie premenných priamo za deklaráciou štruktúry môžem vytvoriť aj premenné anonymného typu.
struct{int a;char b;}temp1,temp2;
túto štruktúru som nijak nepomenoval, a teda premenné temp1 a temp2 sa stávajú premennými nového anonymného typu. (dosť neprehľadné podľa mňa, len som chcel povedať, že to ide :) Ešte na okraj, pokiaľ štruktúra obsahuje iba premenné tak sa dá hneď pri deklarácii aj inicializovať. viď temp2. Ani toto sa však veľmi nepoužíva...
Ak si novú štruktúru pomenujem ako sa patrí, ale počas programu si jej meno prekryjem deklaráciou nového objektu, tak k menu štruktúry (a teda menu nového typu) sa dostanem cez plné meno
struct MenoStruktury
viď ako je definovaný objekt Matka

Nové objekty (premenné po starom) môjho nového typu Clovek je možné definovať buď ako objekty priamo, alebo vytvorením nového smerníka na ne. Myslím si, že pomocou toho smerníka je to "väčšia frajerina :)", ale je to skôr tým, že som z Buildera navyknutý pristupovať k členom pomocou ->. V prípade, že si zadefinujem priamo objekty nového typu (tak ako v prípade objektu Matka), tak k jednotlivým členom štruktúry pristupujem pomocou operátora .

Inicializácia nového objektu spočíva v tom, že nastavím všetkým jeho členom hodnotu takú ako majú mať. Nastavovať však všetky hodnoty ručne, najmä ak viem, že plánujem mať veľa objektov s rovnakými hodnotami, je celkom otrava, a je rozumné si na to vytvoriť funkciu. Samozrejme si môžem vytvoriť funkciu so súborovým rozsahom platnosti (funkcia InitClovek2), a do nej odovzdávať ako parameter smerník (alebo referenciu) na objekt, ktorý chcem inicializovať (v zmysle naplnenia jeho členských parametrov defaultnými hodnotami). Ale, keďže vieme, že členskými objektami štruktúry môžu byť aj funcie, je rozumné si zadefinovať funkciu v rámci štruktúry (resp. aspoň zadeklarovať), tak aby sme mali všetko pokope. (nezdá sa mi rozumné, aby funkcie, ktoré pracujú iba s novým špeciálnym typom boli roztrusené len tak po súbore. Toto už trošku naznačuje peknú črtu objektového programovania - zapuzdrenie)
Ak by som sa rozhodol funkciu v rámci triedy iba deklarovať, tak jej telo je možné zadefinovať mimo štruktúry, s tým, že uvediem jej plné meno, teda vrátane operátora :: Príkladom je funkcia InitClovek

Ku členským parametrom (premenným a funkciám v tomto príklade) sa pristupuje, ako som spomenul hore pomocou operátorov -> alebo . podľa toho či sa jedná o objekt novovytvoreného typu, alebo smerník naň.

Drobná zvláštnosť je v rámci funkcie ShowClovek, ktorá využíva smerník this. Ten je v tomto prípade v skutočnosti nanič, a je tam len na to aby som ukázal, že existuje. Jeho význam spočíva v tom, že keď volám hocijakú členskú funkciu, tak jej pri tomto volaní odovzdávam smerník na objekt, ktorý ju volá. Ak to znie zamotane, tak si stačí v jednoduchosti predstaviť, že namiesto this ako keby bolo napísané Otec, resp &Matka, podľa toho, kto volal funkciu.
Ako vidieť v prípade funkcie InitClovek nie je treba šaškovať s nejakým this, lebo v tomto prípade to ide aj bez neho.

No a nakoniec vidieť, že štruktúry sa dajú priraďovať aj navzájom medzi sebou.

#include "stdio.h"

struct{
int a:2;
unsigned int b:3;
int c:3;        // signed
void ShowField (){printf("\n%d %d %d",a,b,c);}
      }test;


#pragma argsused
int main(int argc, char* argv[])
{
test.a=1;test.b=4;test.c=4;
test.ShowField();

printf("\n%d",sizeof(test));

char pause=getchar();
        return 0;
}
Zaujímavým typom, ktorý možno v rámci štruktúry použiť je bitové pole. Ak na nejakú premennú v štruktúre nepotrebujem celú veľkosť prvku int, ale stačí mi pár bitov, tak to môžem spraviť pomocou bitových polí. Treba však dávať pozor na to, že bitové polia pojmú naozaj len také veľké prvky, na ktoré je ich bitová kapacita dostatočná. Je tiež rozumné definovať aj bezznamienkové typy, ak mi na znamienku nezáleží - vôjde tak toho do bitového poľa viac :) Veľkosť štruktúry sa ráta nejak zvláštne, takže neviem odhadnúť prečo je v tomto prípade práve 4. Ale asi to bude veľkosť typu int. Ak by mali bitov spolu viac (4byte = 32bitov) tak by sa aj veľkosť celého typu zväčšila - v násobkoch veľkosti int (teda 4,8,12...).
V tomto prípade má pole spolu 8bitov a teda vôjde aj do jedného charu. (ak nadefinujem a,b,c typu unsigned char, tak sizeof(test) je 1.

Uniony

Uniony sú podobné ako štruktúry, ale všetky premenné zdieľajú jednu pamäť.
#include "stdio.h"
#include "string.h"

union Clovek{
char meno[20];
char priezvisko[20];
int vek;
int vaha;
int vyska;

void ShowClovek(){
printf("\n------------");
printf("\nMeno:        %s",this->meno);
printf("\nPriezvisko:  %s",this->priezvisko);
printf("\nVek:         %d",this->vek);
printf("\nVyska/Vaha:  %d/%d",this->vyska, this->vaha);
}

void InitClovek();

};

void Clovek::InitClovek(){
strcpy(meno,"");strcpy(priezvisko,"");
vek=0;vaha=0;vyska=0;}


int main(int argc, char* argv[])
{

Clovek *Otec=new Clovek;

strcpy(Otec->meno,"Anton");
        Otec->ShowClovek();
strcpy(Otec->priezvisko,"Novy");
        Otec->ShowClovek();
Otec->vek=34;
        Otec->ShowClovek();
Otec->vaha=82;
        Otec->ShowClovek();
Otec->vyska=182;
        Otec->ShowClovek();

char pause=getchar();

        return 0;
}
Ako vidieť, členské parametre zdieľajú tú istú pamäť v tom zmysle, že keď zmením jednu členskú premennú tak ostatné premenné jej zmenou prepíšem. Toto je preto, lebo všetky členy unionu začínajú na rovnakej adrese.
Uniony nesmú obsahovať virtuálne funkcie, nemôžu sa podieľať na dedičnosti a nesmú obsahovať statické členy.
#include "stdio.h"

union Word{
unsigned short a;
   struct Bytes{
    unsigned char low;
    unsigned char upp;}B;

          }temp;

int main(int argc, char* argv[])
{

temp.a=1;
printf("\nWord:%5d   Low:%5d  High:%5d",temp.a,temp.B.low,temp.B.upp);

temp.a=256;
printf("\nWord:%5d   Low:%5d  High:%5d",temp.a,temp.B.low,temp.B.upp);

temp.a=65535;
printf("\nWord:%5d   Low:%5d  High:%5d",temp.a,temp.B.low,temp.B.upp);

temp.a=0xabcd;
printf("\nWord:%2x Low:%2x   High:%2x",temp.a,temp.B.low,temp.B.upp);

char pause=getchar();

        return 0;
}

Triedy

Tak triedy sú prakticky to isté ako štruktúry. V triedach sa používajú členské funkcie omnoho viac ako v štruktúrach, ale keďže sa dajú členské funkcie definovať v oboch, tak to nie je nič nové...
To čo je však pri štruktúrach vcelku nepríjemné, že neexistujú tzv. privátne členy. (ale aj to sa dá riešiť...) Majme teda štruktúru.
#include "stdio.h"

struct Dolar{
int sk;
void zmennaSk(int dolar,int kurz){
sk=kurz*dolar;}
};

int main(int argc, char* argv[])
{

Dolar *vyplata=new Dolar;
vyplata->zmennaSk(1000,30);

printf("\nVyplata v SK je: %d",vyplata->sk);
vyplata->sk=500;
printf("\nVyplata v SK je: %d",vyplata->sk);

char pause=getchar();

        return 0;
}
Je síce pekné, že som si urobil špeciálnu funkciu na nastavovanie vyplaty v korunách, ale aj tak mám priamo prístup k členskej premennej sk, a môžem si ju nastaviť kedy chcem a ako chcem. Aj bez funkcie. Premenná sk, v tomto prípade nie je až tak kritická, ale celkovo je nepríjemné, že mám možnosť meniť premené z vonka. Triedy toto ošetrujú tým, že ak premenným nenastavím defaultne, že majú byť zvonka prístupné, tak defaultne prístupné zvonka nie sú.
V skutočnosti sa dá nastaviť aj v štruktúre čo je viditeľné zvonka a čo nie, ale triedy majú defaultne nastavné všetko privátne, a teda ak na to zabudnem, nehrozí, že premenná ostane zvonka prístupná.
prístupy existujú private public a protected
public členy sú prístupné v rámci triedy (štruktúry), aj mimo nej, private sú prístupné iba v rámci triedy (štruktúry) a protected členy sú prístupné v rámci triedy (štruktúry), zdedeným triedam (štruktúram), ale nie sú prístupné zvonku.
V rámci konceptov OOP, je vhodné aby čo možno najviac toho bolo private (zapuzdrenosť) a meniť by sa mali dať, iba prostredníctvom verejných členských funkcií.
...
class Dolar{
int sk;
void zmennaSk(int dolar,int kurz){
sk=kurz*dolar;}
};
...
Takže takto vyzerá deklarácia triedy. Nič zložité. V tomto konkrétnom prípade je však táto trieda nanič, lebo keďže všetky členy sú defaultne privátne, neexistuje možnosť ako zvonka nastaviť hodnotu sk. Nedá sa to ani priamo, ani cez funkciu. Nič totiž nie je viditeľné zvonka.
...
class Dolar{
int sk;
public: void zmennaSk(int dolar,int kurz){
sk=kurz*dolar;}
};
...
Toto je už lepšie, ale stále nie veľmi dobré, lebo aj keď premennú sk nastavím, neexistuje možnosť, ako ju vypísať. Najjednoduchšie by bolo dať aj premennú sk public, ale to by som bol tam kde som bol na začiatku.
...
class Dolar{
int sk;
public:
void zmennaSk(int dolar,int kurz){
sk=kurz*dolar;}
int VratVyplatu(){return sk;}
};
...
Deklarácia tejto triedy by teda mala (v rámci zásad OOP) vyzerať takto. K premennej sk sa priamo nedostanem, ale mám možnosť ju meniť, aj vypísať. Funkcia na zmenu možno vyzerá na pohľad zbytočná, a zložitá, ale takto aspoň nezabudnem, že je treba hodnoty kovertovať :). Krása je tiež v tom, že keď sa rozhodnem zmeniť typ premennej sk, napríklad na unsigned int, tak sa to navonok nijak neprejaví a všetko funguje ako má...
Celkovo sú triedy rozhodne dobrá vec, a štruktúry netreba používať (sú v C++ iba kvôli kompatibilite...)

Statické objekty tried

#include "stdio.h"

class Dolar{
int sk;
static int pocetzmien;

public:
void zmennaSk(int dolar,int kurz){
sk=kurz*dolar;
pocetzmien++;
}

int VratPocetZmien(){return pocetzmien;}

int VratVyplatu(){return sk;}
};

int Dolar::pocetzmien;

int main(int argc, char* argv[])
{

Dolar *vyplata=new Dolar;
Dolar *najom=new Dolar;

vyplata->zmennaSk(1000,30);
printf("\nVyplata v SK je: %d",vyplata->VratVyplatu());
vyplata->zmennaSk(2000,30);
printf("\nVyplata v SK je: %d",vyplata->VratVyplatu());
printf("\nPocet zmien je: %d",vyplata->VratPocetZmien());
najom->zmennaSk(500,33);
printf("\nPocet zmien je: %d",vyplata->VratPocetZmien());

char pause=getchar();

        return 0;
}
Statické objekty tried sa správajú troška inak ako statické globálne resp. lokálne premenné. Pri triede je objekt typu static spoločný pre všetky objekty typu trieda, a zároveň nepatrí žiadnermu z nich. static objekt patrí len triede samotnej :) Pekne zamotane napísané, ale je to jednoduché. Proste si vytvorím napríklad horeuvedenú triedu Dolar (tento názov Dolar som nevymyslel najvhodnejšie a o ničom nevypovedá, ale čo už, názov ako každý iný) Povedzme že je v nej statický parameter pocetzmien, typu int. Teraz keď si vytvorím hocikoľko objektov typu Dolar žiaden z nich nebude mať "svoju" premennú pocetzmien. Táto patrí proste triede a je vhodné aby v statickej premennej boli údaje týkajúce týkajúce sa všetkých objektov typu Dolar. V tomto prípade je v premennej uložený počet volaní funkcie zmennaSk. Nie však počet volaní z konkrétnych objektov typu Dolar, ale celkový počet volaní. Teda nech volal funkciu zmennaSk hociktorý objekt, statická premenná sa zvýšila.
Drobnou zvláštnosťou static členov funkcie je to, že musia byť definované aj mimo triedy a to so súborovým rozsahom platnosti (ako globálna premenná). A samozrejme s plným menom :) Teda vrátane mena triedy a operátora ::. No a posledné prekvapenie - aj keď si definujem novú statickú premennú so súborovým rozsahom platnosti, aj tak ju nemožno priamo použiť :) (samozrejme, že ju možno použiť, ale je potrebné ju volať celým menom, teda napr. Dolar::pocetzmien, ale aj to len v prípade, že je tento statický člen public)
A ešte ďalšia zvláštnosť. Statické premenné nemožno inicializovať priamo pri deklarácii v rámci triedy. (to nemožno žiadne členské premenné) Ak by som jej chcel nastaviť nejak počiatočnú hodnotu, musím to urobiť pri definícii tejto statickej premennej na úrovni súboru. Napríklad
int Dolar::pocetzmien=5;
#include "stdio.h"

class Dolar{
int sk;
static int pocetzmien;

public:
void zmennaSk(int dolar,int kurz){
sk=kurz*dolar;
pocetzmien++;
}

static int VratPocetZmien(){return pocetzmien;}

int VratVyplatu(){return sk;}
};

int Dolar::pocetzmien;

int main(int argc, char* argv[])
{

Dolar *vyplata=new Dolar;
Dolar *najom=new Dolar;

vyplata->zmennaSk(1000,30);
printf("\nVyplata v SK je: %d",vyplata->VratVyplatu());
vyplata->zmennaSk(2000,30);
printf("\nVyplata v SK je: %d",vyplata->VratVyplatu());
printf("\nPocet zmien je: %d",Dolar::VratPocetZmien());
najom->zmennaSk(500,33);
printf("\nPocet zmien je: %d",Dolar::VratPocetZmien());

char pause=getchar();

        return 0;
}
Statické funkcie triedy sa analogicky nevzťahujú na konkrétny objekt typu trieda, ale na triedu samotnú. Funkcia VratPocetZmien() je funkcia, ktorá nesúvisí s konkrétnym objektom typu trieda, týka sa všetkých objektov tohoto typu. Volať ju potom síce môžem aj prostredníctvom vyplata->VratPocetZmien, ale je to úplne jedno, pretože sa jej neodovzdáva parameter this, a teda statická funkcia aj tak nevie, kto ju volal. Je možné ju volať aj pod jej plným menom Dolar::VratPocetZmien() a tak sa to aj väčšinou robí. Zaujímavým dôsledkom je, že nemusí teda existovať ani jeden výskyt objektu typu trieda, a aj tak možno funkciu použiť.

Zahniezdené triedy Nested classes

Zahniezdené triedy sa volajú aj vnorené, alebo lokálne, ale slovíčko zahniezdené dobre znie. Ide v jednoduchosti o to, že je možné vytvoriť triedu v inej triede.
class Clovek{
char meno[20];
public:
int vyska;
int vaha;
  class DatumNarodenia{
      int den;int mesiac;int rok;
  //vaha=80;   chyba
                      };
//den=1;       chyba
             };
Premenné v triede Clovek nie sú prístupné v zahniezdenej triede DatumNarodenia, a premenné zo zahniezdenej triedy nie sú prístupné v triede Clovek.
class Clovek{
char meno[20];
public:
int vyska;
int vaha;
static int PocetLudi;
  class DatumNarodenia{
      int den;int mesiac;int rok;
         void Reset(){PocetLudi=0;}
                      };
//den=1;       chyba
             };
Pristupovať sa dá len ku statickým premenným a aj to iba ak sú public.
#include "stdio.h"
#include "string.h"

class Clovek{
char meno[20];
public:
int vyska;
int vaha;
static int PocetLudi;
  class DatumNarodenia{
      int den;
      public:
      int mesiac;int rok;
         void Reset(){PocetLudi=0;
         }
                      };
//den=1;       chyba
             };

int main(int argc, char* argv[])
{

Clovek *Peto=new Clovek;
Peto->vyska=10;
//Peto->den=10;
Clovek::DatumNarodenia *Petrov=new Clovek::DatumNarodenia;
//Petrov->den=10;
Petrov->mesiac=10;

char pause=getchar();

        return 0;
}
V rámci mainu si môžem zadefinovať nového človeka, ale premenné triedy DatumNarodenia, sú stále nedostupné. Ak vytvorím nový objekt triedy DatumNarodenia, tak je možné k jednotlivým premenným pristupovať (ak sú public samozrejme...)
#include "stdio.h"
#include "string.h"

class Clovek{
char meno[20];
public:
int vyska;
int vaha;
static int PocetLudi;
  class DatumNarodenia{
      public:
      int den;int mesiac;int rok;
         void Reset(){PocetLudi=0;
         }
                      }dnr;
void InicializujDatum(int d,int m, int r){
dnr.den=d;
dnr.mesiac=m;
dnr.rok=r;}

void VypisDatum(){
printf("\n%d.%d  %d",dnr.den,dnr.mesiac,dnr.rok);}

             };

int main(int argc, char* argv[])
{

Clovek *Peto=new Clovek;
Peto->vyska=10;
Peto->InicializujDatum(10,1,1990);
Peto->VypisDatum();

char pause=getchar();

        return 0;
}
A takto nejak by sa to asi malo používať. Nielen vytvoriť lokálnu triedu, ale zároveň aspoň jeden objekt z nej a hodnoty vnútornej triedy nastavujem prostredníctvom členských funkcií hlavnej triedy.

Spriatelené funkcie Friend functions

#include "stdio.h"

class Clovek{
 int vek;
 friend SetVek(Clovek *temp, int vstup){temp->vek=vstup;}
public:
 int vyska;
 int vaha;

static void VypisVek(Clovek *temp){printf("\n%d",temp->vek);}
              };

int main(int argc, char* argv[])
{
Clovek *Peto=new Clovek;
SetVek(Peto,20);
Clovek::VypisVek(Peto);

char pause=getchar();

        return 0;
}
Spriatelené funkcie predstavujú alternatívny spôsob prístupu k privátnym parametrom. Funkcia VypisVek je statická len kvôli tomu aby som ukázal, že to ide :) Inak to nemá veľký význam...
...
class Clovek{
 friend SetVek(Clovek *temp, int vstup){temp->vek=vstup;}
 int vek;
  public:
...
Zaujímavé, je že funkcia SetVek dokáže pracovať s premennou vek, aj keď tá bola deklarovaná až neskôr. Toto je spôsobené tým, že funkcia SetVek je nečlenská (v tejto chvíli by predsa mala byť privátna, tak ako je možné, že ju možno používať?...) Funkcia deklarovaná pomocou friend, sa totiž nestáva členskou funkciou triedy ani sa na ňu nevzťahujú špecifikátory public, private a protected. Funkcia je spriatelenou funkciou tejto triedy...
Je dôležité uvedomiť si, že tým že napíšem v rámci triedy friend, určujem kto je priateľom tejto triedy. Ak definujem ako friend nejakú funkciu, tak to neznamená, že táto funkcia je členom tejto triedy (je preto dobré písať jej telo mimo triedy, aby to nevyzeralo, že funkcia je členská) Nemalo by totiž žiaden význam nastaviť členským funkciám aby boli friend (a mali prístup k privátnym parametrom), lebo majú prístup k privátnym parametrom odjakživa. friend iba rozširuje kto ďalší by mal mať prístup k privátnym parametrom triedy, ktorá priateľstvo udeľuje...
#include "stdio.h"

class Muz;

class Zena {
        int vekZena_;
public:
        void test(Muz*);

        };

class Muz {
        int vekMuz_;
        friend void vypisVek(Muz*);
        friend void Zena::test(Muz*);

public:
void setVek(){vekMuz_=22;}

};

void Zena::test(Muz* objekt){printf("\n%d",objekt->vekMuz_);}

void vypisVek(Muz* objekt){printf("\n%d",objekt->vekMuz_);}

int main(int argc, char* argv[])
{
Muz *Peto=new Muz;
Zena *Jana=new Zena;

Peto->setVek();
vypisVek(Peto);
Jana->test(Peto);

char pause=getchar();
        return 0;
}
Priateľstvo je možné udeliť nie len globálnym funkciám, ale aj členským funkciám iných tried (okrem iného...) Funkcia VypisVek je teda obyčajná globálna funkcia, ktorej trieda Muz udelila priateľstvo a dovolila jej teda pristupovat k jej privátnym parametrom. Dôsledkom je, že funkcia VypisVek má plný prístup ku všetkým (teda aj privátnym) parametrom triedy Muz.
Ďalší o kom si trieda Muz myslí, že by mal byť jej priateľ, a udelila mu teda plné právo k svojim privátnym parametrom je istá členská funkcia triedy Zena. Teda konkrétne funkcia test, čo je členská funkcia triedy Zena, má prístup k privátnym parametrom triedy Muz.
Nakoľko chcem pristupovať k privátnym parametrom triedy Muz, ktoré nie sú statické a vzťahujú sa teda na konkrétnu inštanciu triedy Muz, je nutné týmto spriateleným funkciám odovzdávať objekt typu Muz. Aby vedeli ku koho privátnym parametrom to majú vlastne pristupovať...
Vďaka tomu, že členskej funkcii test, potrebujem dodať smerník na objekt typu Muz, vzniká problém, lebo žiadna trieda Muz ešte nebola deklarovaná. Keby som to vymenil, a dal deklaráciu triedy Muz pred triedu Zena, tak by sa prekladaču zase nepáčilo, že chcem udeľovať priteľstvo akejsi ženskej funkcii, ktorá ešte nebola deklarovaná... Riešiť sa to dá tak, že triedu "preddeklarujem". Úplne na začiatku je teda napísané Class Muz; čim som dal prekladaču najavo že sa nemusí báť a niekde mu tú triedu Muz dopodrobna opíšem...
...
class Muz {
        int vekMuz_;
        friend void vypisVek(Muz* objekt)
				{printf("\n%d",objekt->vekMuz_);}
        friend void Zena::test(Muz*);

public:
void setVek(){vekMuz_=22;}

};
...
Ak deklarujem funkciu vypisVek ako priateľskú a zároveň uvediem aj jej telo, tak funkcia je implicitne inline. Kvôli tomu je dobré definovať telá spriatelených funkcií mimo triedy.
#include "stdio.h"

class Clovek{
char meno[20];
public:
int vaha;
int vyska;
friend class DatumNarodenia;

  class DatumNarodenia{
      int den;int mesiac;int rok;
      public:
      void VypisVahu(Clovek* objekt){printf("\n%d",objekt->vaha);}
                      };

             };

int main(int argc, char* argv[])
{
Clovek* Jano=new Clovek;
Jano->vaha=32;
Clovek::DatumNarodenia *temp=new Clovek::DatumNarodenia;
temp->VypisVahu(Jano);


char pause=getchar();
        return 0;
}
Vnorená trieda je priateľskou. Trieda DatumNarodenia má teda prístup k private (aj public) parametrom nadradenej triedy. Nakoľko je však stále potrebné odovzdávať smerník na objekt typu nadradenej triedy nemá to veľký význam...
Taktiež odovzdávam smerník na objekt ktorého premenná vaha nie je private, a mal by k nej prístup aj tak... Toto je len preto, aby som mohol nastaviť hodnotu premennej vaha a neskôr ju vypísať.

Konštantné funkcie

#include "stdio.h"

class Clovek{
char meno[20];
public:
int vyska;
int vaha;
void setVaha(int a){vaha=a;}
void vypisVahu(){printf("\n%d",vaha);}

             };

int main(int argc, char* argv[])
{
const Clovek *Jano=new Clovek;
//Jano->vaha=32;
Jano->setVaha(22);
Jano->vypisVahu();

const Clovek Fero=*Jano;
//Fero.vyska=32;
Fero.setVaha(32);
Fero.vypisVahu();

char pause=getchar();
        return 0;
}
Aj keď som objekty Jano a Fero definoval ako konštantné, je ich stále možné modifikovať prostredníctvom členských funkcií. Nie je pritom dôležité či pracujem priamo s inštanciou triedy Clovek, alebo smerníkom na ňu. (prekladač vydá iba warning)
#include "stdio.h"

class Clovek{
char meno[20];
public:
int vyska;
int vaha;
void setVaha(int a)const{/*vaha=a*/}
void vypisVahu()const{printf("\n%d",vaha);}
             };

int main(int argc, char* argv[])
{
const Clovek *Jano=new Clovek;
//Jano->vaha=32;
Jano->setVaha(22);
Jano->vypisVahu();

const Clovek Fero=*Jano;
//Fero.vyska=32;
Fero.setVaha(32);
Fero.vypisVahu();

char pause=getchar();
        return 0;
}
Ak deklarujem funkciu ako konštantnú tak jednak mi prekladač nedovolí v jej tele napísať nič čo by mohlo konštantný objekt modifikovať, a jednak už nebude mať námietky keď budem túto funkciu volať z konštantnej inštancie triedy. (Dokonca aj nekonštantnej...) Členské funkcie, ktoré nemodifikujú členské premenné, je dobré deklarovať ako koštantné, tak aby ju bolo možné neskôr volať pre konštantné aj nekonštantné objekty.
#include "stdio.h"

class Clovek{
char meno[20];
public:
int vyska;
int vaha;
void setVaha(int a){vaha=a;}
void setVaha(int a)const{printf("Nemozno menit const objekt...");}
void vypisVahu()const{printf("\n%d",vaha);}
             };

int main(int argc, char* argv[])
{
const Clovek *Jano=new Clovek;
//Jano->vaha=32;
Jano->setVaha(22);
Jano->vypisVahu();

char pause=getchar();
        return 0;
}
Ak si vytvorím dve funkcie s rovnakým menom (preťaženie), jednu pre konštantné objekty a jednu pre nekonštantné, môžem ošetriť aby mi prekladač nevyhadzoval chyby. (Namiesto toho ich vyhodím ja :), alebo jednoducho premennú nemodifikujem)

Konštruktory

#include "stdio.h"

class Clovek{

int vek;
public:
void vypisClovek(){printf("\n%d %d %d",vek,vyska,vaha);}
int vyska;
int vaha;

Clovek(){vek=20;vyska=180;vaha=80;}

             };

int main(int argc, char* argv[])
{
Clovek Jano;
Jano.vypisClovek();

char pause=getchar();
        return 0;
}
Konštruktor je špeciálna členská funkcia, ktorá sa volá automaticky keď vytvorím nový objekt. Konštruktor musí byť členská funkcia s menom rovnakým ako je meno triedy. Konštruktor nesmie vracať žiadnu hodnotu (ani void). Nemožno ho teda za žiadnych okolností volať, volá sa totiž sám automaticky, vždy keď vzniká nový objekt, či už chcem, či nie... V príklade hore je zabezpečené, že každý novovzniknutý objekt triedy Clovek, dostane pri vzniku počiatočné hodnoty. Takýto koštruktor je vlastne inicializátor, a nemal by sa v rámci konvencií používať. Namiesto toho by sa hodnoty mali odovzdávať konštruktoru.
Konštruktor nesmie byť deklarovaný ako const ani volatile. V rámci tela konštruktora môžem volať iné členské funkcie.
#include "stdio.h"

class Clovek{

int vek;
public:
void vypisClovek(){printf("\n%d %d %d",vek,vyska,vaha);}
int vyska;
int vaha;

Clovek(int vst1, int vst2, int vst3){vek=vst1;vyska=vst2;vaha=vst3;}
             };

int main(int argc, char* argv[])
{
Clovek Jano(10,20,30);
Jano.vypisClovek();

char pause=getchar();
        return 0;
}
Konštruktor by mal teda vyzerať takto, a hodnoty sa novému objektu môžu odovzdávať priamo v okamihu keď vzniká. Nepríjemné je, že ak tieto hodnoty nezadám, tak prekladač vyhlási chybu...
#include "stdio.h"

class Clovek{

int vek;
public:
void vypisClovek(){printf("\n%d %d %d",vek,vyska,vaha);}
int vyska;
int vaha;

Clovek(int vst1=10, int vst2=20, int vst3=30)
			{vek=vst1;vyska=vst2;vaha=vst3;}
             };

int main(int argc, char* argv[])
{
Clovek Jano;
Jano.vypisClovek();
const Clovek Fero;
Fero.vypisClovek();

Clovek *Petko = new Clovek[20];

char pause=getchar();
        return 0;
}
Je teda dobré v rámci deklarácie konštruktora zadať "default" hodnoty, a teda ak hodnoty nezadám, tak nevznikne chyba. Dokonca je možné vytvoriť aj koštantný objekt, a "nie je" ho potrebné inicializovať, a aj tak prekladač nevyhlási chybu. (v skutočnosti ho inicializuje konštruktor...)
Konštruktor je volaný a funguje dokonca aj pri vytváraní dynamických polí objektov...

Statické objekty globálne sú konštruované ešte pred spustením programu. Statické objekty lokálne, sú konštruované pri ich deklarácii)

#include "stdio.h"

class Clovek{

int vek;
public:
void vypisClovek(){printf("\n%d %d %d",vek,vyska,vaha);}
int vyska;
int vaha;

Clovek(int vst1=10, int vst2=20, int vst3=30)
			{vek=vst1;vyska=vst2;vaha=vst3;}
Clovek(Clovek& rhs){vek=rhs.vek;vyska=rhs.vyska;vaha=rhs.vaha;}
             };

int main(int argc, char* argv[])
{
Clovek Jano;
Jano.vypisClovek();
Clovek Fero(5,5,5);
Fero.vypisClovek();

Clovek Jozo(Fero);
Jozo.vypisClovek();

char pause=getchar();
        return 0;
}
Špeciálny prípad konštruktora je copy konštruktor, ktorého vstupným parametrom je iný existujúci objekt. (Vstupným argumentom konštruktora však nemôže byť objekt typu ktorý vytvára. Musím teda objekt odovzdávať cez referneciu, alebo cez smerník.)
Ak vytvorím teda konštruktorov viac (preťaženie) a jeden z nich bude aj copy konštruktor, môžem sa pri vytvorení nového objektu rozhodnúť či nechcem skopírovať už nejaký existujúci.
Zaujímavé je, že keď copy konštruktor nevytvorím, tak aj tak si ho kompilátor vytvorí sám. Ak teda vložím riadok
Clovek(Clovek& rhs){vek=rhs.vek;vyska=rhs.vyska;vaha=rhs.vaha;}
do komentára, výsledok programu je ten istý...
Ak by však trieda obsahovala dynamicky alokované premenné, napríklad smerník ktorý by vznikal v rámci konštruktora (pomocou new), tak defaultný copy konštruktor by mi skopíroval aj tento smerník. Ak by som uvoľnil dynamicky alokovaný smerník v pôvodnom objekte, ešte stále mi ukazuje na nealokované miesto v skopírovanom objekte. Ak by som vytvoril aj pôvodný aj kopírovaný objekt taktiež dynamicky, tak pri uvoľnovaní pamäti a delete týchto objektov by som dvakrát chcel deletovať to isté miesto... Jednoducho ak sú v triede aj dynamické premenné, neoplatí sa spoliehať sa na defaultný copy konštruktor... (viď ďalej)
...
class Temp{
public:
int* ptr;
int a;
void setPtr(int in){*ptr=in;}
void showMeClass(){
        printf("\n %d %d",a,*ptr);}
            };
...
Toto je príklad triedy, ktorá obsahuje dynamickú premennú ptr. Funkcia setPtr nastavuje tejto dynamickej premennej hodnotu, ale keďže premennej ptr nebola vyhradená pamäť, tento program môže spôsobiť iba problémy...
class Temp{
public:
int *ptr;
int a;
void setPtr(int in){ptr=new int(in);}
void showMeClass(){
        printf("\n %d %d",a,*ptr);}
            };
Lepšia definícia funkcie setPtr by teda vyzerala takto. Najprv vyhradí pamäť pre premennú ptr, a až potom jej priradí hodnotu.
#include "stdio.h"

class Temp{
public:
int *ptr;
int a;
void setPtr(int in){ptr=new int(in);}
void showMeClass(){
        printf("\n %d %d",a,*ptr);}
            };

int main(int argc, char* argv[])
{
Temp firstObject;
firstObject.a=10;
firstObject.setPtr(40);
firstObject.showMeClass();

Temp secondObject(firstObject);
secondObject.showMeClass();
printf("\nNasleduje modifikacia druheho objektu...");
*secondObject.ptr=66;
firstObject.showMeClass();
secondObject.showMeClass();

char pause=getchar();

        return 0;
}
Pri volaní implicitného copy konštruktora sa objekt firstObject skopíruje do secondObject. Na prvý pohľad je všetko v poriadku a vznikla skutočne identická kópia.
Ak však modifikujem dynamickú premennú ptr druhého objektu (resp. hociktorého z objektov) modifikujem zároveň aj dynamickú premennú ptr prvého objektu (resp. toho druhého z objektov...) Toto je spôsobené tým, že defaultný copy konštruktor spravil plytkú kópiu shallow copy a teda obe premenné ptr zdieľajú rovnaké miesto v pamäti.
Ani toto však nemusí byť až, taký problém, pretože na modifikáciu premennej ptr, sme predsa vytvorili špeciálnu funkciu setPtr, ktorá problémy s alokáciou pamäti rieši... Ak modifikujem *secondObject.ptr pomocou funkcie setPtr, a napíšem teda
secondObject.setPtr(66);
všetko je "v poriadku".
Aby som predišiel týmto problémom, je dobré vytvoriť si vlastný konštruktor a copy konštruktor, ktorý sa postará o alokáciu pamäte pre premenné. Možno znie zvláštne, že aj konštruktor, ale to je kvôli tomu aby sa pamäť pre dynamickú premennú ptr alokovala iba raz - keď objekt vznikne.
V predošlom príklade sa totiž pamäť alokuje zakaždým, keď objekt modifikujem, a neuvoľnuje sa nikde...
#include "stdio.h"

class Temp{
public:
int *ptr;
int a;
Temp(){ptr=new int;}
Temp(Temp& rhs){ptr=new int;*ptr=*rhs.ptr,a=rhs.a;}
void setPtr(int in){*ptr=in;}
void showMeClass(){
        printf("\n %d %d",a,*ptr);}
            };

int main(int argc, char* argv[])
{
Temp firstObject;
firstObject.a=10;
firstObject.setPtr(40);
firstObject.showMeClass();
printf("\nVytvaram novy objekt");
Temp secondObject(firstObject);
secondObject.setPtr(66);
firstObject.showMeClass();
secondObject.showMeClass();

char pause=getchar();

        return 0;
}
Tento príklad je už čiastočne ošetrený. Vždy pri vytvorení novej inštancie typu Temp sa automaticky alokuje pamäť pre dynamickú členskú premennú ptr. Pri volaní copy konštruktora sa novovytváranému objektu taktiež alokuje pamäť a teda všetko by malo byť v poriadku...
#include "stdio.h"

class Temp{
public:
        int *ptr;
        int a;

        Temp(int vst=0){ptr=new int;a=vst;}
        Temp(Temp& rhs){ptr=new int;*ptr=*rhs.ptr,a=rhs.a;
			printf("\nCopyConst&");}
        Temp(Temp* rhs){ptr=new int;*ptr=*rhs->ptr,a=rhs->a;
			printf("\nCopyConst*");}

        void setPtr(int in){*ptr=in;}
        void showMeClass(){printf("\n %d %d @ %d",a,*ptr,ptr);}
            };

Temp foo(Temp obj){return obj;};

int main(int argc, char* argv[])
{
Temp* ob1 = new Temp;
ob1->a=10;
ob1->setPtr(20);
ob1->showMeClass();

Temp ob2(*ob1);
ob2.showMeClass();

Temp* ob3 = new Temp(ob1);
ob3->showMeClass();

Temp ob5=ob2;

Temp ob4;
ob4=ob2;
ob4.showMeClass();

foo(ob4);

char pause=getchar();

        return 0;
}
Kvôli ešte väčšiemu pohodliu som si vytvoril copy konštruktor aj pre dynamické aj pre obyčajné objekty typu Temp. Je možné pozorovať, kedy sa volá ktorý copy konštruktor. Copy konštruktor sa volá aj v prípade priraďovania pri deklarácii. V riadku Temp ob5=ob2; sa teda copy konštruktor volá tiež...
Problém však stále nastáva ak kopírujem objekty cez obyčajné priradenie =. V tom prípade sa nevolá ani jeden z copy konštruktorov, ale robí sa plytká kópia a objekt do ktorého kopírujem začína zdieľať okrem iného aj priestor pre uloženie dynamickej premennej... Kopírovanie cez = je teda natoľko "silné", že ak zmením na konci v programe hodnotu *ob4.ptr, mením zároveň hodnotu *ob2.ptr...
Toto je spôsobené tým, že v prípade priraďovania sa nevytvára nový objekt. Copy konštruktor sa volá iba v prípade (a tých prípadov je dosť) že sa vytvára nový objekt...
Copy konštruktor sa volá aj v prípade, že odovzdávam funkcii hodnotu. (pretože vtedy sa tiež vytvára kópia objektu) Viď funkciu foo. Vždy keď volám foo, volá sa aj copy konštruktor. Takisto, ak funkcia vracia objekt tak sa vytvára jeho kópia - opäť cez copy konštruktor... V tomto prípade sa teda copy konštruktor volá dvakrát...
Keby trieda obsahovala dynamické parametre, ktorým copy konštruktor alokuje novú pamäť, tak by sa tento copy konštruktor volal aj v prípade odovzdávania, alebo vracania hodnôt funkcií. Dynamickým premenným týchto tried by copy konštruktor automaticky alokoval pamäť, ale nikde by táto pamäť nebola uvoľňovaná... Nie je teda veľmi rozumné aby do funkcie vstupovali priamo objekty (namiesto toho je lepšie radšej odovzávať, alebo vracať objekty)

V programe je možné vytvárať aj dočasné objekty. Ak teda potrebujem napríklad funkcii foo dodať nejaký objekt typu Temp tak tento vytvorím volaním konštruktora.
foo(Temp(8));
Dočasný objekt bude existovať iba v rámci funkcie. Dočasný objekt teda po použití zaniká. Ak by som ho náhodou chcel používať ďalej musím si ho (napriklad copy konštruktorom) skopírovať do iného objektu. Opäť mám známy problém, že konštruktor mi alokoval pamäť, ale nikto ju nikde neodalokoval...

#include "stdio.h"

class Temp{
public:
        int *ptr;
        int a;

        Temp(){ptr=new int;}
        Temp(int in){ptr=new int;a=in;}
        void showMeClass(){printf("\n %d %d @ %d",a,*ptr,ptr);}
            };


Temp generate(){
return Temp(10);}

int main(int argc, char* argv[])
{
Temp objekt=generate();
objekt.showMeClass();

generate();

char pause=getchar();

        return 0;
}
Celkom zaujímavé je používať dočasné objekty ako návratovú hodnotu funkcií. (Ak nie je nutné skutočne vytvárať v rámci funkcie nový objekt...) Tento príklad vygeneruje pomocou konštruktora Temp::Temp(int) objekt, a hneď naplní členskú premennú objektu hodnotou. Tento dočasný objekt je návratovou hodnotou funkcie, a možno ho napríklad priradiť inému novovytvorenému objektu. (Neužitočné, ale dá sa... :)

Konverzie objektov

Občas sa môže hodiť konvertovať novovytvorené objekty na štandardné typy alebo štandardné typy na objekty. Majme napríklad triedu komplexné čísla. Bolo by celkom dobré mať možnosť priraďovať komplexným číslam reálne čísla (čo sú tiež komplexné čísla s nulovou imaginárnou zložkou), alebo napríklad priraďovať reálnym číslam komplexné čísla (s tým, že by sa vracala absolútna hodnota...)
#include "stdio.h"

class Complex{
public:
        float re;
        float im;

        Complex(float first=0, float second=0){re=first;im=second;}
        Complex(int first=0, int second=0){re=first;im=second;}
        void showMeClass(){printf("\n Re:%f Im:%f",re,im);}
            };

int main(int argc, char* argv[])
{
Complex a(1,1);
a.showMeClass();
int b=2;
a=b;
a.showMeClass();
float c=3.14;
a=c;
a.showMeClass();

char pause=getchar();

        return 0;
}
Konvertovanie štandardných typov na objekty sa deje pomocou konštruktorov. Keď priraďujem objektu iný typ hľadá sa vhodný konštruktor, a ak sa nájde uplatní sa. Ak by som do objektu priraďoval premennú typu, pre ktorú neexistuje konštruktor, a ani by sa nedala skonvertovať na nejaký typ, pre ktorý konštruktor existuje, prekladač by vyhlásil chybu...
#include "stdio.h"
#include "math.h"

class Complex{
public:
        float re;
        float im;

        Complex(float first=0, float second=0){re=first;im=second;}
        Complex(int first=0, int second=0){re=first;im=second;}
        void showMeClass(){printf("\n Re:%f Im:%f",re,im);}

        operator double()
        {return sqrt(re*re+im*im);}
        operator char*()
        {return "Nemozno konvertovat cplx cislo na text";}

            };

int main(int argc, char* argv[])
{
Complex a(1,1);
a.showMeClass();
float b=a;
printf("\nAbs Value is: %f",b);
printf(a);

char pause=getchar();

        return 0;
}
Ak potrebujem konvertovať objekt typu Complex na iné objekty, je to možné zbezpečiť pomocou členských konverzných funkcií. Tieto sú bežné členské funkcie, akurát sú deklarované so slovom operator a nepíše sa pri nich návratový typ (ten je zrejmý...)
V tomto prípade som si upravil aj konverziu komplexné číslo->reťazec s tým že sa ako reťazec vracia chybová hláška. Bolo by možné samozrejme preťažiť priamo funkciu printf, ale toto riešenie je výhodné v tom, že všetko je zapuzdrené v rámci triedy.
#include "stdio.h"
#include "math.h"

class Complex{
public:
        float re;
        float im;

        Complex(float first=0, float second=0){re=first;im=second;}
        Complex(int first=0, int second=0){re=first;im=second;}
        void showMeClass(){printf("\n Re:%f Im:%f",re,im);}

        operator int()
        {return (int)re;}
        operator void*()
        {return NULL;}

            };

int main(int argc, char* argv[])
{
Complex a(1,1);
//if(a)printf("a is true");   //chyba
if(a==1)printf("a is true");

char pause=getchar();

        return 0;
}
Pri definovaní konverzných funkcií treba byť opatrný aby nedošlo k viaczmyselnej deklarácii, resp. je potom potrebné konverzie používať v správnom kontexte. V príklade hore by sa totiž nedalo odhadnúť, či if(a) očakáva int, alebo void* a tak by prekladač vyhlásil chybu. Ak však v priamo v ife naznačím, že čakám int, prekladač vie presne, ktorú konverziu má volať.

Inicializácie objektov

#include "stdio.h"

class Complex{
public:
        float re;
        float im;

        Complex(float first=0, float second=0){re=first;im=second;
                printf("\nPouzity defaultny float konstruktor");}
        Complex(Complex& rhs){re=rhs.re;im=rhs.im;
                printf("\nPouzity & copy konstruktor");}
        Complex(Complex* rhs){re=rhs->re;im=rhs->im;
                printf("\nPouzity & copy konstruktor");}
        void showMeClass(){printf("\n Re:%f Im:%f",re,im);}
            };

int main(int argc, char* argv[])
{
Complex a;                      a.showMeClass();
Complex b(10);                  b.showMeClass();
Complex c(1.1,2.2);             c.showMeClass();
Complex d=12;                   d.showMeClass();
Complex e(d);                   e.showMeClass();
Complex f=c;                    f.showMeClass();
Complex* g=new Complex;         g->showMeClass();
Complex* h=new Complex(3);      h->showMeClass();
Complex* i=new Complex(3,4.5);  i->showMeClass();
Complex* j=new Complex(d);      j->showMeClass();
Complex* k=new Complex(&d); k->showMeClass();
Complex l(g);                   l.showMeClass();
Complex m(*g);                  m.showMeClass();
Complex n[5] = {1,
                Complex(),
                e,
                Complex(2,3.5)};
                                n[0].showMeClass();
                                n[1].showMeClass();
                                n[2].showMeClass();
                                n[3].showMeClass();
                                n[4].showMeClass();

char pause=getchar();

        return 0;
}
Tento vyčerpávajúci zoznam možností (ktorý možno nie je ani kompletný) hovorí za všetko. Možnosti inicializácie objektov je skutočne veľa. V prípade, že inicializujem pole objektov môžem to urobiť vymenovaním jeho prvkov, pričom ich možno vymenovávať "hocijakým" spôsobom. V prípade, že niektoré (posledné) prvky nevymenujem, inicializujú sa sami použitím impicitného konštruktora. Samozrejme, že to funguje iba pre statické prvky - dynamické sa vytvárajú pomocou new, a inicializujú sa použitím príslušného konštruktora.

Deštruktory

Deštruktor je presne opačná funkcia ku konštruktoru, a volá sa vtedy keď premenná zaniká. (Napríklad ak deletujem dynamicky vytvorený objekt). Automatické objekty zanikajú pri konci bloku. Deštruktor sa deklaruje podobne konštruktoru, akurát pred meno sa dá ~.
Deštruktor opäť nemôže vracať hodnotu (ani void) a nesmie mať ani žiadne vstupné parametre. Nemôže byť const ani volatile, ale môže byť virtuálny... Z deštruktora je možné volať ostatné členské funkcie. V prípade poľa sa deštruujú najskôr prvky, ktoré boli vytvorené posledné.
#include "stdio.h"

class Temp{
public:
        int *ptr;
        int a;

        Temp(){ptr=new int;
               printf("\nKonstruktor: pamat bola alokovana");}
        Temp(int in){ptr=new int;a=in;}
        void showMeClass(){printf("\n %d %d @ %d",a,*ptr,ptr);}
        ~Temp(){delete ptr;
               printf("\nDestruktor: pamat bola uvolnena");}
            };

int main(int argc, char* argv[])
{
{Temp objekt1;}         //automaticky objekt v bloku

Temp();                 //docasny objekt
/*
{Temp original;
Temp kopia(original);}  //problem plytkej kopie
*/
Temp objekt2;           //objekt v maine, zanikne ked skonci main

char pause=getchar();

        return 0;
}
Deštruktor má v tomto príklade na starosť odalokovanie pamäte. Na prvý pohľad ubudlo dosť starostí a nikde v programe neostáva alokovaná pamäť pre objekty, ktoré už zanikli, ale nanešťastie deštruktor (v tomto prípade) chce občas uvoľňovať, aj to čo by nemal. Problém však nie je v samotnom deštruktore, ale v implicitnom copy konštruktore, ktorý vyrába iba plytkú kópiu. Vďaka tomu majú dva rôzne objekty, alokované to isté miesto v pamäti. Keď zanikne prvý z nich miesto sa uvoľní (pre oba, keďže zdieľajú rovnaké miesto), keď zanikne druhý z nich deštruktor sa snaží uvoľňovať, to čo už raz bolo uvoľnené... Riešením v tomto prípade je samozrejme copy konštruktor, ktorý bude robiť nielen plytkú kópiu, ale bude aj prideľovať pamäť novým objektom.

(c) Wray 2006