Šta je novo?

Pocetnicko C++ pitanje

WebWolf

Čuven
Učlanjen(a)
18.09.2004
Poruke
3,824
Poena
735
Moja oprema  
CPU & Cooler
AMD Ryzen 5600 & Scythe Mugen
Matična ploča
MSI X470 Gaming Pro Carbon
RAM
Kingston HyperX Predator 16GB 3200MHz
GPU
GeForce RTX™ 3060 Ti GAMING OC PRO 8G
Storage
Samsung 970 Evo Plus 1TB & Samsung 970 Evo Plus 500GB
PSU
Corsair RM650x
Kućište
NZXT H500
Miš & tastatura
Cooler Master MK730 & Razer Basilisk v3
Mobilni telefon
Pixel 7 Pro
Pametni uređaji
Xiaomi Roborock 6
Xiaomi Air Purifier 3H
Pristup internetu
  1. Optički internet
Kod:
class Head{
public:
	int c = 0; //greska
	virtual void Add(){c++;}
	virtual void Count() = 0;
};
class Tail : public Head{
	void Add(){	c+=2;}
	void Count(){printf("%d", c);	}
};

Zadatak je pronaci gresku u ovom kodu. Greska je ovo int c=0; Da bi ovako mogla da se deklarise mora da bude static i const, ali onda je nemoguce menjati je u nastavku koda (u main, II zadatak). Kako je najlakse resiti ovu gresku tj. inicijalizvati je na nulu?
 
Reseno. Samo sam dodao konstruktor Head() {c=0;}
 
Napraviš kontruktor koji će inicijalizovati tu promenljivu na 0:

Kod:
class Head{
public:
	int c = 0; //greska
	virtual void Add(){c++;}
	virtual void Count() = 0;

        Head();
};


Head::Head()
{
    c = 0;
}

ili (ako je recimo c const):

Kod:
Head::Head() : c(0)
{

}
 
To sam i uradio. Medjutim, sada imam drugi problem. Treba napraviti ovaj program da radi. Mozda ce mi biti jasnije izjutra, kada sam pametniji 🙂
Kod:
#include <iostream>
using namespace std;
class Head{
public:
	int c;
	virtual void Add(){c++;}
	virtual void Count() = 0;
	Head() {c=0;}
};
class Tail : public Head{
	void Add(){	c+=2;}
	void Count(){printf("%d", c);	}
};
void main(){
	Head* h = new Tail();
	h->Add();
	h->Count();	
	Tail t = *h;
	t.Add();
	t.Count();

}
 
A sta program treba da radi? :-/
Neko vezba sa virtual metodama?

Bolje je praviti konstruktor sa inicijalizacijom gore:
Kod:
Head()
:c(0)
{}

U ovom slucaju je int, pa je isto. Ali da nije neki primitivan tip, onaj tvoj kod bi ga prvo inicijalizovao defaultnim konstruktorom, pa posle pozvao operator dodele...
 
Poslednja izmena:
Kod:
class Head
{
public:
	int c;
	virtual void Add() { c++; }
	virtual void Count() = 0;
	Head();
};

Head::Head()
{
	c = 0;
}

class Tail : public Head
{
public:
	void Add();
	void Count();
};

void Tail::Add()
{
	c+=2;
}

void Tail::Count()
{
	printf("%d\n", c);
}


int _tmain(int argc, _TCHAR* argv[])
{
	Head* h = new Tail();
	h->Add();
	h->Count();	
	Tail t =  *(Tail *)h;
	t.Add();
	t.Count();

	return 0;
}


Da bi uradio Tail t = *h, potreban ti je eksplicitni cast. Implicitno je moguće dodeliti vrednost pointera koje je tipa izvedene klase pointeru koji je tipa osnovne klase, ali obrnuto - mora eksplicitni cast.

Takođe u definiciji klase Tail si zaboravio public. U tom slučaju članovi klase su private.
 
Poslednja izmena:
_tmain?
_TCHAR?
Jel to visual studio? To nije standardni C++.
 
Izvinjavam se, nisam bio dovoljno precizan. Treba da nadjem sta ce program dati kao izlaz (rec je o usmenom delu ispita OOP, znaci nemam racunara kod sebe). U svakom slucaju, ne treba menjati main. Onako kako sam ga napisao, tako treba da bude, ali treba da izmenim/dodam nesto u ovim klasama. Znaci, ovo sto sam pokazao je kod koji sam dobio, nisam ga sam napisao 🙂 .
 
Jeste VC++.

Ali mislim da ovakav implicitni cast ne bi trebao da radi u svakom slučaju - nezavisno od kompajlera.

U slučaju da grešim i da main treba da ostane isti, samo dodaj public: u deklararaciji za Tail.

Program ti se izvršava ovako:

1. Head* h = new Tail();

Kreira se novi objekat tipa Tail sa adresom adr1 (poziva se default Tail() konstruktor - koga nemaš 🙂, posle toga default Head() konstruktor koji inicijalizuje adr1->c na 0). Adresa adr1 se smešta u promenljivu h.

2. h->Add();

Poziva se Tail::Add() funkcija koja adr1->c poveća za 2 (c==2).


3. h->Count();

Poziva se Tail::Count() funckija koja ispisuje adr1->c (2).

4. Tail t = *h;

Sporna linija za koju stvarno mislim da ne bi trebalo da radi (nisam više na poslu, a kod kuće nemam gcc da probam sa njim). Ali u principu objekat koji se nalazi na adr1 kopira u objekat t koji je tipa Tail i koji će se nalaziti na adr2.
Ovde je problem što je h pointer na objekat tipa Head, *h je objekat tipa Head. Tako da mi objektu tipa Tail dodeljujemo objekat tipa Head. Ne postoji implicitni cast koji će da izvrši ovu konverziju. Zato je potrebno prvo eksplicitno konvertovati pointer u Tail *.


5. t.Add();

Poziva se Tail:Add() za objekat na adr2 i adr2->c se povećava za 2.

6.t.Count();

Poziva se Tail::Count() za objekat na adr2 i ispisuje se adr2->c (4);


edit:
Na kraju je h->c == 2 i t.c == 4.
 
Poslednja izmena:
U pravu si. Ta linija (Tail t = *h; ) i ne radi, ona me i buni...

Btw. treba uzeti u obzir da ovo zaista ima gresku. Kako je zadatak sa nekog prethodnog ispita, moguce je da je na ispitu usmeno data ispravka.
 
Poslednja izmena:
Jedno pitanje. Recimo da neka klasa ima metodu koja poziva delete this. Primetio sam da ako pozovem tu metodu nad objektom podklase, biće pozvan destruktor nadklase. Kako se može srediti da se poziva destruktor one podklase nad čijim objektom je pozvana dotična metoda (koja poziva delete this). Ako proglasim destruktor za virtual popijem kriptičnu grešku kompajlera. 🙂

EDIT: Heh, rešen problem. Samo sam deklarisao virtuelni destruktor, nisam ga implementirao.
 
Poslednja izmena:
'delete this;' je jako losa praksa i treba biti oprezan sa tim.
1. to smes da radis samo sa dinamicki alociranim objektima.
2. vlasnik objekta nema pojma da je objekat obrisan
3. ako se pointer objekat nalazi u nekom kontejneru (niz, lista, mapa, ...) ostace da visi pointer na nepostojeci objekat
4. ako se objakat nalazi u nekom kontejneru (niz, lista, mapa, ...) pojavice se problem kada se kontejner bude brisao. Nemas pojma da li su svi objekti validni pa ce se ponovo pozvati desktrukor nad necim sto je vec obrisano.
 
Nazad
Vrh Dno