Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

Nasledjivanje i konstruktori u C++

[es] :: C/C++ programiranje :: Nasledjivanje i konstruktori u C++

[ Pregleda: 6338 | Odgovora: 3 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

Akademik

Član broj: 116514
Poruke: 20
79.101.48.*



Profil

icon Nasledjivanje i konstruktori u C++07.08.2009. u 10:30 - pre 178 meseci
Zasto ovaj programcic nece da se iskompajlira? Prijavljuje da je problem u konstruktoru Casopis, ali zbog cega? I kako prepraviti program da ovo radi?

Znaci, hocu da klasa Casopis nasledi klasu Publikacija, redefinise metodu ispis() klase Publikacija, zatim da u toku izvrsavanja (dakle, dinamicki), na osnovu korisnickog zahtjeva se pozove metoda ispis() ili iz Publikacije ili iz klase Casopis.
Naizgled, prosta stvar, nasledjivanje, konstruktori, inicijalizacije, ali....
Kada postojece konstruktore zamjenim default konstruktorima (tj. onim bez parametara), to ce sve da radi, incijalizacija ce se obaviti. Medjutim, sta ako hocu da napravim 15 objekata neke klase, pa nece svi imati default vrijednosti...treba nekad da se inicijalizuju i drugacijim vrijednostima od default-nih.

Dakle, evo koda:
==========================================================================

#include<iostream>
using namespace std;

class Publikacija{

private:
int a1;

public:
Publikacija(int a){
a1 = a;
}

void ispis(){
cout <<"\n\ta1: "<<a1
<<endl;
}
};

class Casopis: public Publikacija{

private:
int a1;

public:
Casopis(int a){
a1 = a;
}

void ispis(){
cout <<"\na1: "<<a1
<<endl;
}
};

void ispisi_sve(Publikacija *p){
p->ispis();
cout<<endl;
}

main(){

Publikacija *p;
string izbor;

Publikacija objekat1(438);
Casopis objekat2(212);

cout <<"\nIz koje klase da pozovem metod ispis()? ";
cin >> izbor;
if(izbor == "publikacija") {p = &objekat1; ispisi_sve(p); }
else {p = &objekat2;
ispisi_sve(p);}
}
=========================================================

Hvala.
 
Odgovor na temu

Mihajlo Cvetanović
Beograd

Moderator
Član broj: 37636
Poruke: 1249



+96 Profil

icon Re: Nasledjivanje i konstruktori u C++07.08.2009. u 10:59 - pre 178 meseci
Ovde ima nekoliko problema. Mislim da je najbitniji što nisi načisto šta zaista želiš od svog koda. Recimo da sam ja programer, a ti neko ko nešto hoće a nema blage veze o programiranju, i sad mi reci šta ti u stvari želiš. Možeš da koristiš reči Časopis i Publikacija, ali ne i reči Nasleđivanje i Konstruktor.

Na stranu to, funkcija ispis ti nije virtuelna, tako da će p->ispis uvek pozivati funkciju Publikacija::ispis. Drugo, imaš članicu a1 u obe klase, što je moguće ali i zbunjujuće, i ja to ne bih radio, i uostalom ako to a1 ima istu svrhu u obe klase onda ti je dovoljno samo jedno a1 u osnovnoj klasi. Treće, kad se kreira objekat klase Casopis onda mora da se kreira (i to pre Casopisa) i osnovni objekat klase Publikacija, tako da ili ćeš imati default konstruktor za klasu Publikacija, ili u konstruktoru za Casopis mora eksplicitno da se navede koji konstruktor klase Publikacija se koristi, i sa kojim parametrima:

Code:
Casopis(int a) : Publikacija(a){
a1 = a;
}


Ako želiš samo različit ispis za istu promenljivu a1 onda:
- ukloni a1 iz klase Casopis, kao i ovo a1 = a iz prethodnog koda, ali ostavi pozivanje konstruktora Publikacije
- stavi da je Publikacija::ispis virtuelna
- promeni Publikacija::a1 da bude protected umesto private
 
Odgovor na temu

Akademik

Član broj: 116514
Poruke: 20
79.101.48.*



Profil

icon Re: Nasledjivanje i konstruktori u C++07.08.2009. u 20:10 - pre 178 meseci
Nista mi nije jasno. FUCK!
Zasto ja moram iz klase Casopis da pozivam konstruktor klase Publikacija? Zar klasa Casopis nema svoj konstruktor Casopis?!
Citao sam da je redosled pozivanja konstruktora kod kreiranja objekta izvedene klase takav da se prvo poziva konstruktor osnovne klase, a potom kons. izvedene.
Medjutim, taj proces mi nije bas najjasniji.
Recimo da klasa Publikacija ima sledece atribute: id i naslov, a klasa Casopis pored ovih atributa i neke njoj svojstvene atribute: atr1 i atr2.
Ja bi htjeo recimo, da mi kons. klase Publikacija inicijalizuje atribute id i naslov, a klasa Casopis da inicijalizuje samo atr1 i atr2. Kako se to izvodi?
Kako bi ti uopste osmislio ovakav program?
Mozda je ovo oko konstruktora sve normalno i logicno, mozda sam se ja jednostavno navikao na C, pa sad ovo nikako da shvatim...
 
Odgovor na temu

Goran Arandjelovic
Beograd

Član broj: 29116
Poruke: 387
79.101.180.*



+9 Profil

icon Re: Nasledjivanje i konstruktori u C++07.08.2009. u 21:27 - pre 178 meseci
Citat:
Akademik: Nista mi nije jasno. FUCK!
Zasto ja moram iz klase Casopis da pozivam konstruktor klase Publikacija? Zar klasa Casopis nema svoj konstruktor Casopis?!
Citao sam da je redosled pozivanja konstruktora kod kreiranja objekta izvedene klase takav da se prvo poziva konstruktor osnovne klase, a potom kons. izvedene.
Medjutim, taj proces mi nije bas najjasniji.
Recimo da klasa Publikacija ima sledece atribute: id i naslov, a klasa Casopis pored ovih atributa i neke njoj svojstvene atribute: atr1 i atr2.
Ja bi htjeo recimo, da mi kons. klase Publikacija inicijalizuje atribute id i naslov, a klasa Casopis da inicijalizuje samo atr1 i atr2. Kako se to izvodi?
Kako bi ti uopste osmislio ovakav program?
Mozda je ovo oko konstruktora sve normalno i logicno, mozda sam se ja jednostavno navikao na C, pa sad ovo nikako da shvatim...


Moraš da pozoveš i konstruktor klase Publikacija zato što se instanca (objekat) klase Casopis sastoji i iz podobjekta Publikacija i iz podobjekta Casopis... i taj objekat u memoriji (uprošćeno) izgleda tačno kao na slici.

Možeš ti na tu instancu da pokazuješ i pokazivačem tipa Publikacija i pokazivačem tipa Casopis, ali je to instanca Casopisa...
Ako pokazuješ na objekat pokazivačem tipa Publikacija tada dolaze do izražaja virtualne funkcije. Probaj recimo da pozivaš dole pc1->NekaMetoda() i pc2->NekaMetoda i skloni "virtual" da vidiš šta se tačno dešava.

Objekat

Evo ga jedan scenario:

Code:

#include <iostream>
using namespace std;

class Publikacija
{
    public:
        Publikacija()
        {
            this->attr1 = 10;
            this->attr2 = 15;
        }

        Publikacija(int x, int y)
        {
            this->attr1 = x;
            this->attr2 = y;
        }

        virtual void NekaMetoda()
        {
            cout << this->attr1 << endl;
            cout << this->attr2 << endl;
        }

        virtual ~Publikacija()
        {
            cout << "Destruktor: Publikacija" << endl;
        }
    private:
        int attr1;
        int attr2;
};

class Casopis : public Publikacija
{
    public:
        /* Jeste da se ovde ne vidi, ali se ovde prvo poziva podrazumevani konstruktor klase Publikacija: Publikacija() */
        Casopis()
        {
            this->attr3 = 3;
            this->attr4 = 7;
        }
        
        /* Možeš i da izostaviš pozivanje ovog konstruktora Publikacija koji inicijalizuje attr1 i attr2
        ali onda MORA da postoji podrazumevani konstruktor Publikacija() */

        Casopis(int a, int b, int c, int d) : Publikacija(a, c)
        {
            this->attr3 = b;
            this->attr4 = d;
        }

        Casopis(int a, int b) : Publikacija(a+b, a-b)
        {
            this->attr3 = a;
            this->attr4 = b;
        }

        virtual void NekaMetoda()
        {
            cout << this->attr3 << endl;
            cout << this->attr4 << endl;
        }
        
        virtual ~Casopis()
        {
            cout << "Desktruktor: Casopis" << endl;
        }
    private:
        int attr3;
        int attr4;
};

int main()
{
    Publikacija *p1 = new Publikacija();
    Publikacija *p2 = new Publikacija(22, 33);

    Casopis *c1 = new Casopis();
    Casopis *c2 = new Casopis(10, 20, 30, 40);
    Casopis *c3 = new Casopis(66, 77);

    Publikacija *pc1 = new Casopis(88, 99);
    Publikacija *pc2 = new Casopis();

    /* itd... */

    p1->NekaMetoda(); // testiraj pozivanjem ove metode i vidi šta se ispisuje
    
    /* itd... */


    /* Zbog ovoga MORAŠ da imaš virtualni destruktor */
    delete p1;
    delete c2; // da nemaš virtualni destruktor, obrisao bi samo deo objekta koji odgovara klasi Casopis (vidi sliku!)
    delete c3;
    delete c1;
    delete p2;
    delete pc2; // opet, da nemaš recimo virtualni destruktor, obrisao bi samo deo objekta koji odgovara klasi Publikacija
    delete pc1;

    return(0);
}


Recimo ovde:
Code:

Casopis(int a, int b, int c, int d) : Publikacija(a, c)


Mogao si da izostaviš pozivanje konstruktora klase Publikacija, ali bi morao da postoji podrazumevani konstruktor Publikacija().
Ako nisi sam napisao podrazumevani konstruktor Publikacija(), on se sam generiše sa praznim telom samo ako ne postoji ni jedan drugi konstruktor u klasi Publikacija.

Dakle, konstruktori... prvo se pozivaju konstruktori baznih klasa pa onda izvedenih... a kod destruktora (virtualnih) je to obratno. A i vidiš zašto moraš da imaš virtualne destruktore. To je za početak dobra i poželjna praksa. Naravno, ove klase nisu kompletne, ali odgovaraju tvom pitanju.


[Ovu poruku je menjao Goran Arandjelovic dana 07.08.2009. u 22:48 GMT+1]
 
Odgovor na temu

[es] :: C/C++ programiranje :: Nasledjivanje i konstruktori u C++

[ Pregleda: 6338 | Odgovora: 3 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.