Šta je novo?

ETFovski C++

jddipqd

Čuven
Učlanjen(a)
17.10.2000
Poruke
2,555
Poena
725
Ovo je zvanično rešenje jednog ispitnog zadatka, ali ono ne može da se iskompajlira (MS VC++ 7)
Da li oni nas pogrešno uče ili sam ja lud?

Kod:
#include <iostream>
using namespace std;

class Predmet {
  static int ukId; int id;
  virtual void pisi(ostream &d) const =0;
public:
  Predmet () { id = ++ukId; }
  Predmet (const Predmet &) { id = ++ukId; }
  virtual ~Predmet () {}
  Predmet &operator= (const Predmet &) { return *this);
  int operator! () const { return id; }
  virtual Predmet *kopija () const =0;
  friend ostream &operator<< (ostream &d, const Predmet &p)
    { p.pisi (d); return d; }
};

int Predmet::ukId = 0;

class Celi : public Predmet {
  int vr;
  void pisi (ostream &d) const { d<<vr; }
public:
  Celi (int v=0) { vr = v; }
  int operator+ () const { return vr; }
  Celi *kopija () const { return new Celi (*this); }
};

class GIndeks {};

class Zbirka {
public:
  virtual ~Zbirka () {}
  virtual const char *vrsta () const =0;
  virtual int operator+ () const =0;
  virtual Zbirka &operator+= (const Predmet &p) =0;
  virtual Predmet *& operator[](int i)=0;
  virtual const Predmet *operator[] (int i) const =0;
  virtual Zbirka &operator~ () =0;
  friend ostream &operator<< (ostream &d, const Zbirka &z);
};

ostream &operator<< (ostream &d, const Zbirka &z) {
  d << z.vrsta() << '[';
  for (int i=0; i<+z; i++) { d<<*z[i]; if (i!=+z-1) d<<','; }
  return d << ']';
}

class Niz: public Zbirka {
  Predmet **niz; int duz, kap;
  void kopiraj (const Niz &n);
  void brisi () { ~*this; delete[] niz; }
public:
  Niz (int k=10) { niz = new Predmet* [kap = k]; duz = 0; }
  Niz (const Niz &n) { kopiraj (n); }
  ~Niz () { brisi (); }
  Niz & operator= (const Niz &n) {
    if (this!=&n){ brisi(); kopiraj(n); }
    return *this;
  }
  const char *vrsta () const { return "Niz"; }
  int operator+ () const { return duz; }
  Niz & operator+= (const Predmet &p);
  Predmet *& operator[] (int i) {
    if (i<0 || i>=duz) throw GIndeks ();
    return niz[i];
  }
  const Predmet * operator[] (int i) const {
    if (i<0 || i>=duz) throw GIndeks ();
    return niz[i];
  }
  Niz & operator~ ();
};

void Niz::kopiraj (const Niz &n) {
  niz = new Predmet* [kap=n.kap]; duz = n.duz;
  for (int i=0; i<duz; i++) niz[i] = n.niz[i]->kopija();
}

Niz & Niz::operator+= (const Predmet &p){
  if (duz == kap) {
    Predmet **pom = new Predmet* [kap+=(kap<100?10:0.1*kap)];
    for (int i=0; i<duz; i++) pom[i] = niz[i];
    delete [] niz; niz = pom;
  }
  niz[duz++] = p.kopija();
  return *this;
}

Niz & Niz::operator~ () {
  for (int i=0; i<duz; delete niz[i++]);
  duz = 0; return *this;
}

int main () {
  Niz niz (20); cout << "Niz? ";
  while (1) {
    int k; cin >> k;
  if (k == 9999) break;
    niz += k;
  }
  cout << niz << endl;
  while (1) {
    int i; cout << "Indeks? "; cin >> i;
  if (i == 9999) break;
    try {
      cout << "id=" << !*niz[i] << ", vr=" << *niz[i] << endl;
    } catch (GIndeks) {
      cout << "*** Neispravan indeks!\n";
    }
  }
  return 0;
}

Dobijam sledeće greške:
Kod:
------ Build started: Project: nizovi, Configuration: Debug Win32 ------
Compiling...
nizovi.cpp
nizovi.cpp(5) : error C2864: 'ukId' : only const static integral data members can be initialized inside a class or struct
nizovi.cpp(20) : error C2504: 'Predmet' : base class undefined
nizovi.cpp(43) : error C2804: binary 'operator <<' has too many parameters
nizovi.cpp(43) : error C2333: 'Predmet::operator`<<'' : error in function declaration; skipping function body
nizovi.cpp(75) : error C3254: 'Predmet' : class contains explicit override 'kopiraj' but does not derive from an interface that contains the function declaration
nizovi.cpp(75) : error C2838: 'kopiraj' : illegal qualified name in member declaration
nizovi.cpp(80) : error C3254: 'Predmet' : class contains explicit override '+=' but does not derive from an interface that contains the function declaration
nizovi.cpp(80) : error C2838: '+=' : illegal qualified name in member declaration
nizovi.cpp(90) : error C3254: 'Predmet' : class contains explicit override '~' but does not derive from an interface that contains the function declaration
nizovi.cpp(90) : error C2838: '~' : illegal qualified name in member declaration
nizovi.cpp(114) : fatal error C1075: end of file found before the left brace '{' at 'nizovi.cpp(4)' was matched

nizovi - 11 error(s), 0 warning(s)
---------------------- Done ----------------------
    Build: 0 succeeded, 1 failed, 0 skipped
 
virtual ~Predmet () {}

treba da stoji virtual ~Predmet();
znači bez zagrada.

Predmet &operator= (const Predmet &) { return *this);

Posle *this umesto ) treba da stoji }, i nedostaje ;

Treba da stoji:
Predmet &operator= (const Predmet &) { return *this; }


Posle ove dve ispravke (u principu su ovo sintaksne greške)... ostaje samo još jedna:

Na jednom mestu se koristi operator += sa integerom, a koliko vidim nije definisan je samo za Predmet (i nigde nema konstruktora konverzije Predmet u integer).


Na brzinu sam pogledao, kaži ako sam nešto propustio.
 
Poslednja izmena:
zeleni_zub je napisao(la):
virtual ~Predmet () {}

treba da stoji virtual ~Predmet();
znači bez zagrada.
Prazno telo ne smeta. Prolazi i sa i bez.

zeleni_zub je napisao(la):
Predmet &operator= (const Predmet &) { return *this);

Posle *this umesto ) treba da stoji }, i nedostaje ;

Treba da stoji:
Predmet &operator= (const Predmet &) { return *this; }
Ne mogu da verujem da ovo nisam video :wall:

zeleni_zub je napisao(la):
Na jednom mestu se koristi operator += sa integerom, a koliko vidim nije definisan je samo za Predmet (i nigde nema konstruktora konverzije Predmet u integer).
Ovo sam izvalio... treba u stvari onako kako sam i sam pretpostavio na početku: u klasama Zbirka i Niz treba da se koriste objekti klase Celi a ne klase Predmet (što je i logično jer je Predmet apstraktna klasa).

Da student ovako nešto napiše na ispitu ne da bi pao nego strašno :smackbum:
 
jddipqd je napisao(la):
Prazno telo ne smeta. Prolazi i sa i bez.

Izvini moja greška... učinilo mi se da je destruktor ponovo definisan niže u programu.

-----------
P.S. LOL.... tek sam sada provalio šta sam napisao gore (a sada je kasno da editujem post):
zeleni_zub je napisao(la):
a koliko vidim nije definisan je samo za Predmet

Treba da stoji 'definisan je samo...' Ono 'nije' je višak.

Ali važno je da smo se razumeli.
:D
 
Poslednja izmena:
Kod:
Niz & Niz::operator+= (const Celi &p){
  if (duz == kap)
    kap < 100 ? kap = 10 : kap *= 1.1;
  niz[duz++] = p.kopija();
  return *this;
}

Još jedno pitanjce:
Kako bih kao novi element u niz dodao onaj objekat koji sam prosledio operatorskoj f-ji, a ne njegovu kopiju?
 
jddipqd je napisao(la):
Kod:
Niz & Niz::operator+= (const Celi &p){
  if (duz == kap)
    kap < 100 ? kap = 10 : kap *= 1.1;
  niz[duz++] = p.kopija();
  return *this;
}

Još jedno pitanjce:
Kako bih kao novi element u niz dodao onaj objekat koji sam prosledio operatorskoj f-ji, a ne njegovu kopiju?

Ako sam te dobro razumeo ti bi da u niz smestiš neki objekat koji je dinamički kreiran negde u programu.

Pa prvo promenjiva niz bi trebalo da ti bude niz pokazivača na Predmet. Znači:
Predmet **niz;
niz= Predmet *[n];

i posle samo ubacuješ adrese Predmeta u niz:

niz[duz++]=&p.

Samo moraš da paziš... ako ubaciš neki objekat koji nisi kreirao sa new recimo:

Niz n1;

void f1(void)
{
Predmet p; //Znam da je Predmet virtuelna klasa, ali me sada mrzi da gledam šta je izvedeno iz nje... :p
n1+=p;
}

..... kada se završi izvršavanje ove f-je Predmet p biva uništen (oslobađa se memorija) i ti u nizu imaš neku adresu na kojoj nemaš objekat tipa Predmet. I kada se izvrši recimo niz[x]->"neka f-ja iz klase Predmet", ode sve u... ,)




Spava mi se (mnogo je kasno)... pa ako je malo konfuzno izvini.
 
Poslednja izmena:
Još pitanja...

U čemu je problem sa ovim parčetom koda?
Dobijam grešku "error C2662: 'Kvadar::V' : cannot convert 'this' pointer from 'const Kvadar' to 'Kvadar &'"

Kod:
class Predmet {
public:
	virtual bool operator<(const Predmet &p) const =0;
}
class Kvadar: public Predmet {
	double a, b, c;
public:
	Kvadar(double aa, double bb, double cc) {
		a = aa; b = bb; c = cc;
	}
	double V() { return a*b*c; }
	bool operator<(const Kvadar &k) const {
		return V() < k.V();
	}
}
 
Kod:
class Predmet {
public:
	virtual bool operator<(const Predmet &p) const =0;
};

class Kvadar: public Predmet {
	double a, b, c;
public:
	Kvadar(double aa, double bb, double cc) {
		a = aa; b = bb; c = cc;
	}
	double V() CONST { return a*b*c; }
	bool operator<(const Kvadar &k) const {
		return this->V() < k.V();
	}
};
 
Poslednja izmena:
Pošto silver nije bio mnogo pričljiv da ti pojasnim malo bolje... :p

bool Kvadar::eek:perator<(const Kvadar &k) const

kao argument ima referencu na konstantan objekat tipa Kvadar. Za sve konstante objekte dozvoljeno je samo pozivanje konstantnih funkcija (da bi se obezbedilo da se podaci unutar objekta ne menjaju). Da to nije slučaj, ti bi mogao da za Kvadar k pozoveš funkciju koja bi mu promenila a,b i c, i onda bi konstanti objekti izgubili svrhu... Zato je dobra praksa da sve funkcije članice koje ne menjaju ništa u objektu označavaš sa const.
 
Postajem dosadan :)

Da li može da se set (i uopšte bilo koji container) deklariše kao static?
Ako napišem
Kod:
#include <set>
using namespace std;
class GImePostoji {};
class Promenljiva: {
	double vrednost;
	string ime;
	static set<string> listaImena;
public:
	Promenljiva(string iIme, double v = 0) {
		if (listaImena.count(iIme) != 0)
			throw GImePostoji();
		listaImena.insert(iIme);
		ime = iIme;
		vrednost = v;
	}
}
void main() {
	Promenljiva p("x", 10);
}
prođe kompajler, ali se pobuni linker:
Kod:
(Izrazi error LNK2001: unresolved external symbol "private: static class std::set<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > Promenljiva::listaImena" (?listaImena@Promenljiva@@0V?$set@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@U?$less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@A)
 
jddipqd je napisao(la):
Da li može da se set (i uopšte bilo koji container) deklariše kao static?

Može...Samo si zaboravio da definišeš taj static objekat. Static objekat u nekoj klasi je zajednički za sve objekte tog tipa tako da ne može biti definisan u konstruktoru... moraš posle deklaracije klase da ubaciš (u ovom primeru koji si poslao pre main f-je):

set<string> Promenljiva::listaImena;


---------------------
Recimo da imaš:

Kod:
class X
{
 public:
  X();

  void inc(void) { c++; }

  ~X();

 private:
  static int c;
}

int X::c=10;

void main(void)
{
 X x1,x2,x3;   // x1, x2 i x3 imaju zajednički int c
 x1.inc();      // c=11
 x2.inc();     //  c=12
 x1.inc();     //  c=13
 x3.inc();     //  c=14
 cout << X::c; //ispisuje 14
}

P.S. A ono "Postajem dosadan..."... :p :D Pa šta bi se pisalo u ovoj sobi? :)

Uostalom ovo je puta manje dosadno nego 1.00E99 put videti pitanja: "jel bolji AMD ili Intel" ili "ajde izvadite svoje kristalne kugle i kažite mi koliko mogu da overklokujem svoj procesor pošto mene mrzi da probam", i sl.... :D ,)
 
Poslednja izmena:
Izvini... gore u primeru static int c ne treba da je private nego public.
 
Hvala na strpljenju :) Ima ja ovako do 12tog dok mi ne prođe ispit :p

Kod:
class Naredba {
protected:
	string naziv;
};
class Probna: public Naredba {
	long t;
public:
	Probna() {}
	Probna(string n, long tt = 0) {
		naziv = n; t = tt;
};
class Red {
	queue<Naredba*> red;
public:
	Naredba* uzmi() {
		Naredba *pom = red.front();
		red.pop();
		return pom;
	}
};
class Interpreter {
    Red red;
public:
	Interpreter(Red &r) {
		red = r;
	}
	void operator!() {
		Probna pom;
		pom = *red.uzmi(); // Greška
	}
};
U redu se nalaze Probne. Uzmi vraća pointer na Naredbu, a ja hoću da dobijem Probnu. Pretpostavljam da treba neki cast ali ne znam kako
 
Poslednja izmena:
jddipqd je napisao(la):
U redu se nalaze Probne. Uzmi vraća pointer na Naredbu, a ja hoću da dobijem Probnu. Pretpostavljam da treba neki cast ali ne znam kako

Možeš to uraditi sa eksplicitnim cast-om:

pom = * (Probna *)red.uzmi();

Ali je prilično velika greška ovako nešto napisati (edit: u stvari nije tolika greška ako si baš siguran šta radiš - u svakom slučaju nije dobro rešenje):

U redu se nalaze pokazivači na objekte tipa Naredba. Ti ovde iz klase Naredba imaš izvedenu samo klasu Probna, ali recimo da imaš i klasu Sistemska (class Sistemska : public Naredba) i još tri četiri klase - sve izvedene iz klase Naredba. U red možeš da smestiš pokazivače na bilo koji objekat koji je izveden iz Naredbe. I ti (dok se izvršava program) ne možeš da znaš da li će red.front() da ti vrati pokazivač na objekat tipa Probna, Sistemska ili neki drugi tip... Tako da može da se desi da red.front() vrati pokazivač na objekat tipa Sistemska a ti ga prebaciš u u Probna *.

Mnogo bolje rešenje je u klasi Naredba staviti funkciju, recimo Izvrši(), i posle je samo preklapati u izvedenim klasama. Tako da ne moraš da razmišljaš koja vrsta naredbe je izašla iz queue-a, nego uzimaš pokazivač na Naredbu, i izvršiš f-ju Izvrši, a mehanizam preklapanja će da osigura da se poziva odgovarajuća f-ja.

Kod:
Naredba *n;

n = red.uzmi();
n->Izvrši();  // svaka izvedena klasa ima svoju funkciju izvrši.

A ako te baš zanima kog tipa je naredba, ubaci u klasu Naredba f-ju ID() koja vraća neki ID broj naredbe (svakom tipu dodeliš jedan ID broj). I naravno f-ju ID preklopiš posle u svakoj izvedenoj klasi.
 
Poslednja izmena:
Jedna samo napomena glede ovog 'explicitnog' casta - u danasnjem C++u su takve C-like cast operacije oznacene kao depreciated. Umesto toga treba koristiti 'nove' cast operatore - static_cast, const_cast, reinterpret_cast i dynamic_cast. U ovom slucaju, za shetnju po liniji nasledjivanja se koristi dynamic_cast:

CIzvedena *izvedeni_obj = dynamic_cast<CIzvedena *>(&CBazna); // oblik prema pointeru
CIzvedena &izvedeni_obj = dynamic_cast<CIzvedena &>(CBazna); // oblik prema referenci

za slucaj da je vazi:
class CIzvedena: public CBazna {...}
 
silverglider je napisao(la):
Jedna samo napomena glede ovog 'explicitnog' casta - u danasnjem C++u su takve C-like cast operacije oznacene kao depreciated. Umesto toga treba koristiti 'nove' cast operatore - static_cast, const_cast, reinterpret_cast i dynamic_cast. U ovom slucaju, za shetnju po liniji nasledjivanja se koristi dynamic_cast:

CIzvedena *izvedeni_obj = dynamic_cast<CIzvedena *>(&CBazna); // oblik prema pointeru
CIzvedena &izvedeni_obj = dynamic_cast<CIzvedena &>(CBazna); // oblik prema referenci

za slucaj da je vazi:
class CIzvedena: public CBazna {...}

verujem ja tebi nego de si to procitao da se informishemo i mi malo?
 
To je vec nekoliko godina deo vazeceg ANSI standarda, tj. poslednje revizije. Uzmes bilo koju (ANSI) C++ knjigu novijeg datuma i tu je sve lepo opisano.

Mislim da sam za knjigu Danny Kaleva The ANSI/ISO C++ Professional Programmer's Handbook video da se moze naci i u pdf obliku, a sama knjiga odlicno pokriva i objasnjava dodatke i izmene u samom jeziku. Napomena samo - za srednji i napredni nivo, odnosno ne za one kojima treba objasnjavati sta je varijabla, a sta konstanta, nego za ljude koji znaju da programiraju, ali zele da rasciste neke stvari oko znacenja pojedinih konstrukcija.
 
silverglider je napisao(la):
To je vec nekoliko godina deo vazeceg ANSI standarda, tj. poslednje revizije. Uzmes bilo koju (ANSI) C++ knjigu novijeg datuma i tu je sve lepo opisano.

Mislim da sam za knjigu Danny Kaleva The ANSI/ISO C++ Professional Programmer's Handbook video da se moze naci i u pdf obliku, a sama knjiga odlicno pokriva i objasnjava dodatke i izmene u samom jeziku. Napomena samo - za srednji i napredni nivo, odnosno ne za one kojima treba objasnjavati sta je varijabla, a sta konstanta, nego za ljude koji znaju da programiraju, ali zele da rasciste neke stvari oko znacenja pojedinih konstrukcija.

:d taj sam ... zahvaljujem
 
Nazad
Vrh Dno