[ Pretender @ 22.08.2003. 15:50 ] @

Sledeci program radi OK, ali bih ipak imao par pitanja.


Code:


// Sve sto jednom gradjaninu moze zatrebati
// vezano za pravougaonik

# include <iostream.h>
# include <conio.h>

typedef unsigned short int USHORT;
typedef unsigned long int ULONG;
enum BOOL {FALSE, TRUE};
enum CHOICE {DrawRect = 1, GetArea,
             GetPerim, ChangeDimensions, Quit};

//Deklaracija klase pravougaonik

class Rectangle
{
    public:
       //konstruktori
       Rectangle (USHORT width, USHORT height);
       ~Rectangle();

       //metode pristupa
       USHORT GetHeight() const {return itsHeight;}
       USHORT GetWidht() const {return itsWidht;}
       ULONG GetArea() const {return itsHeight * itsWidht;}
       ULONG GetPerim() const {return 2*itsHeight + 2*itsWidht;}
       void SetSize(USHORT newWidht, USHORT newHeight);

       //Razne metode (koje se ovde ne koriste)
       void DrawShape()const;

    private:
        USHORT itsWidht;
        USHORT itsHeight;
};                          //kraj deklaracije klase


//Implementacija metoda klase

void Rectangle::SetSize(USHORT newWidht, USHORT newHeight)
{
    itsWidht = newWidht;
    itsHeight = newHeight;
}

Rectangle::Rectangle(USHORT widht, USHORT height)
{
    itsWidht = widht;
    itsHeight = height;
}

Rectangle::~Rectangle() {}

//deklaracija f-ja NECLANICA

USHORT DoMenu();
void DoDrawRect(Rectangle);
void DoGetArea(Rectangle);
void DoGetPerim(Rectangle);


void main()
{
      //inicijalizuje pravougaonik na 30, 5
      Rectangle theRect(30,5);

      USHORT choice = DrawRect;
      USHORT fQuit = FALSE;

      while (!fQuit)
      {
          choice = DoMenu();
          if (choice < DrawRect || choice > Quit )
          {
              cout << "\n Nevazeci izbor, molim Vas pokusajte ponovo.\n\n";
              continue;
          }
          switch (choice)
          {
          case DrawRect:
             DoDrawRect(theRect);
             break;
          case GetArea:
             DoGetArea(theRect);
             break;
          case GetPerim:
             DoGetPerim(theRect);
             break;
          case ChangeDimensions:
             USHORT newLenght, newWidht;
             cout << "\n Nova sirina: ";
             cin >> newWidht;
             cout << " \n Nova visina: " ;
             cin >> newLenght;
             theRect.SetSize(newWidht, newLenght);  

             DoDrawRect(theRect);        //opciono
             break;
          case Quit:
             fQuit = TRUE;
             cout << "\nIzlazak....\n\n";
             break;
          default:
             cout << "Greska u izboru!\n";        //ne vidim kako ikada  
             fQuit = TRUE;
             break;
          }                // kraj switch
      }             // kraj while
getch();
}            // kraj main


// Definicija f-ja NECLANICA

USHORT DoMenu()
{
   USHORT choice;
     cout << "\n\n ***Meni***\n";
     cout << "(1) Nacrtaj pravougaonik\n";
     cout << "(2) Izracunaj povrsinu\n";
     cout << "(3) Izracunaj obim\n";
     cout << "(4) Promeni velicinu\n";
     cout << "(5) Izlaz\n";
   cin >> choice;
   return choice;
}

void DoDrawRect(Rectangle theRect)
{
   USHORT height = theRect.GetHeight();
   USHORT widht = theRect.GetWidht();
   cout << "\n";
   for (USHORT i=0; i<height; i++)
   {
       for (USHORT j=0; j<widht; j++)
          cout << "*";
       cout << "\n";
   }
}


void DoGetArea(Rectangle theRect)
{
    cout << "Povrsina: " << theRect.GetArea() << endl;
}

void DoGetPerim(Rectangle theRect)
{
    cout << "Obim: " << theRect.GetPerim() << endl;
}


Autor je skrenuo paznju da ChangeDimensions ne moze pozvati f-ju, kao npr. DoChangeDimensions(), jer bi u tom sl. dimenzije bile promnjene za lokalnu kopiju pravougaonika u DoChangeDimensions() a ne za pravougaonik u main().

Ovo mi nije bas jasno.
Radi unifikacije u switch case, bilo bi bas zgodno da postoji upravo takva f-ja.

Ako bi postojala f-ja DoChangeDimensions(), koja bi bila identicna bloku ispod case ChangeDimensions (znaci radila bi:
theRect.SetSize(newWidht, newLenght); ne vidim kako ovo ne bi promenilo pravougaonik u main().

I jos nesto. Nije mi jasno kada moze doci do default-a u switch-u.

I jos nesto (2). Zasto su deklarisane nabrojane konstante tipa BOOL ?
Mislim, ocigledno je, da bi se koristile u while testu kao (0) i (1), ali zar TRUE i FALSE nisu sluzbene reci koje bi mogle da se koriste direktno u while testu ? (pa dakle ako je fQuit=FALSE onda je !fQuit=TRUE)


Hvala
[ filmil @ 22.08.2003. 16:13 ] @
Ne znam odakle ti ovaj kod, ali ako je iz neke knjige, preporučio bih da je ako ne baciš, bar odložiš u stranu u korist nečeg boljeg, jer je opasno zastarela a bogami i daje neke sasvim pogrešne savete.

Najpre što se tiče pitanja za konstante, tip bool i vrednosti true i false su deo savremenog jezika c++. Ovaj program očigledno pojma nema o tome.

Međutim gora stvar je što se u programu koriste eksterne funkcije za obavljanje nečega što treba da bude isključivo u nadležnosti samog objekta. Bilo koje ispisivanje, promena vrednosti i slično, u obliku složenije funkcije treba napisati kao funkciju članicu -- ako ne direktno samog objekta pošto nekada način crtanja nije vezan samo za objekat već i za uređaj na kom se crta ali svejedno, onda nekog drugog objekta koji je zadužen za crtanje (na primer canvas ili kako se već gde zove). Ako su potrebni različiti algoritmi onda opet NE treba koristiti case strukture već izvesti različite klase u kojima se koristi polimorfizam.

I napokon odgovor na tvoje pitanje: koliko vidim objekti se u funkcije prenose po vrednosti (by value), što znači da se za potrebe funkcije pravi lokalna kopija objekta. To automatski znači da kako je ovde deklarisano, ti NE MOŽEŠ menjati direktno objekat unutar funkcija jer u funkciji radiš nad njegovom lokalnom kopijom. Problem je i u tome što se na ovaj način naručuje kopiranje celog objekta za potrebe funkcije (i to default konstruktorom za kopiranje što u nekim slučajevima nije ono što želiš) što može da bude problem ako je objekat veliki prema ukupnoj veličini steka. Treba razmisliti o prenosu objekta po imenu (by reference).


f
[ Dragi Tata @ 22.08.2003. 16:20 ] @
Citat:
Međutim gora stvar je što se u programu koriste eksterne funkcije za obavljanje nečega što treba da bude isključivo u nadležnosti samog objekta. Bilo koje ispisivanje, promena vrednosti i slično, u obliku složenije funkcije treba napisati kao funkciju članicu


Filipe, C++ nije Java.

http://www.cuj.com/documents/s=8042/cuj0002meyers/

http://www.codeproject.com/useritems/nonmemberfnoo.asp
[ brcha @ 22.08.2003. 16:28 ] @
Kao prvo, ovaj kod radi samo na DOSu bez ikakvog razloga. Evo ti patch da radi i pod GNU Com (fajl sam nazvao pretender.cc, a patchujes ga komandom patch -Np1 < pretender.diff)
pretender.diff:
Code:

diff -Naur old/pretender.cc new/pretender.cc
--- old/pretender.cc    2003-08-22 17:10:52.000000000 +0200
+++ new/pretender.cc    2003-08-22 17:11:46.000000000 +0200
@@ -4,10 +4,20 @@
 // vezano za pravougaonik
 
 # include <iostream.h>
+#ifdef __GNUC__ 
+# include <curses.h>
+#else
 # include <conio.h>
+#endif
 
 typedef unsigned short int USHORT;
 typedef unsigned long int ULONG;
+#ifdef FALSE
+#undef FALSE
+#endif
+#ifdef TRUE
+#undef TRUE
+#endif
 enum BOOL {FALSE, TRUE};
 enum CHOICE {DrawRect = 1, GetArea,
              GetPerim, ChangeDimensions, Quit};
@@ -61,7 +71,7 @@
 void DoGetPerim(Rectangle);
 
 
-void main()
+int main()
 {
       //inicijalizuje pravougaonik na 30, 5
       Rectangle theRect(30,5);
@@ -109,6 +119,7 @@
           }                // kraj switch
       }             // kraj while
 getch();
+return 0;
 }            // kraj main
 
 


Drugo, slazem se sa filmilom, nema razloga da se pozivaju eksterne funkcije kad to sve moze da se nagura u objekat (ili ako originalni objekat nema te osobine, nasledis ga i dodas ih).

Trece, naravno treba koristiti reference (znaci funkcije deklarises kao void DoDrawRect(Rectangle& theRect)) ili pointere ako je u pitanju neki stariji C++.

Pozdrav
Filip
[ Dragi Tata @ 22.08.2003. 16:36 ] @
Umalo da zaboravim

http://www.gotw.ca/publications/mill02.htm
[ Dragi Tata @ 22.08.2003. 16:39 ] @
Citat:
brcha:
nema razloga da se pozivaju eksterne funkcije kad to sve moze da se nagura u objekat (ili ako originalni objekat nema te osobine, nasledis ga i dodas ih).


Aaaaaaaaaaaaahhhhhhhhhhhhhhhh!!!!!

Trčim u WC da plačem - valjda niko neće da mi traži dva dinara (dolara).
[ brcha @ 22.08.2003. 16:58 ] @
Izvini, jel nije lepse da se kaze theRect.draw() nego DoDrawRect(theRect)?

Nisam rekao da je u svakom slucaju bolje da budu funkcije unutar objekta, ali ovde je lepse, po meni.
[ Reljam @ 22.08.2003. 17:08 ] @
Nemanja, ne mogu bas da se slozim sa tobom. Cini mi se da je ovde vise diskusija o licnim ukusima nego o tome sta je bolje. Ja licno vise volim da stavljam stvari u objekte nego van njih, ali sumnjam da tu moze da se dokaze da je nesto bolje a nesto gore. Takodje ne mislim da je primarna funkcija OOa sakrivanje pristupa, ali siguran sam da bi i oko toga mogli dugo da se raspravljamo ;)

Nego sto se tice clanka na codeprojectu i stringova: postoji i treca opcija, a to je da se metode tipa Insert, Trim, Replace, itd koje ne menjaju objekat budu static, recimo ovako:

string a, b, c;
a=String.Replace(b,c);

Na taj nacin su svi srecni (i ovce na broju sto bi rekla narodna poslovica): OO puristi imaju sve metode u objektu, a oni kojima smeta to sto Trim naizgled deluje kao da utice na stanje stringa dobijaju nesto sto je ociglednije.

Mada opet, to je sve samo stvar ukusa.
[ Dragi Tata @ 22.08.2003. 17:21 ] @
Žao mi je gospodo, ali nije u pitanju "stvar ukusa" i "šta je lepše", već je jednostavna činjenica da pametna upotreba funkcija ne - članica unapređuje dizajn. Meyers ide tako daleko da predlaže sledeći algoritam:

Code:

if (f needs to be virtual)
   make f a member function of C;
else if (f is operator>> or
         operator<<)
   {
   make f a non-member function;
   if (f needs access to non-public
       members of C)
      make f a friend of C;
   }
else if (f needs type conversions
         on its left-most argument)
   {
   make f a non-member function;
   if (f needs access to non-public
       members of C)
      make f a friend of C;
   }
else if (f can be implemented via C's
         public interface)
   make f a non-member function;
else
   make f a member function of C;



U članku na Code Project-u sam predložio malo relaksiraniji pristup ovom problemu koji uzima u obzir i čitljivost koda i "labav" odnos objekata, ali tvrdim da se funkcije ne-članice ne koriste dovoljno u programerskoj praksi zbog nekih ideoloških gluposti.

Relja, statičke funkcije nisu isto što i funkcije ne - članice. One imaju pristup privatnim članovima klase, a to je loše. Osim toga, samo po sebi je loše gurati u klasu funkcije koje ne treba da budu članice klase samo da bi "OO puristi" bili zadovoljni. Uostalom, pravi "OO puristi" i ne koriste C++, već SmallTalk :)
[ Pretender @ 22.08.2003. 18:14 ] @
Hvala na odgovorima.

Izvinjavam se ako sam izazvao CyberWar163, nisam hteo.

Mislim da razumem zasto Vam ovaj program ne izgleda optimalno.
On predstavlja rezime do sada predjenih oblasti (7 dana) u knjizi (C++ za 21 dan - Jesse Liberty). Tako da verovatno ne pretenduje da bude savrsen, nego da prikaze sto vise razlicitih `munja`(npr. poslednje su obradjene upravo SWITCH strukture). Neki od koncepata koje pominjete (kao npr.pokazivaci) upravo slede.

Sto se tice gornje problematike, nisam siguran da razumem kako f-ja pristupa SetSize(newWidht, newSize), moze da promeni objekat theRect (u kojem je deklarisana) ako je pozvana direktno iz main(), a ne moze ako je pozvala neka druga f-ja. After all, ona jeste f-ja pristupa tog objekta sta god da je pozove- ali ako se ovde radi o enkapsulaciji "na delu" OK, usvojicu to tako.

Pod pretpostavkom da sam gore `pogodio`, da li mogu da zakljucim da ako zelim da promene afektuju objekt- pozivam odgovarajucu pristupnu f-ju direktno, a ako to ne zelim pozivam doticnu f-ju iz neke druge (naravno, na ovom nivou znanja, bez pokazivaca, itd).

U vezi brchinog dobronamernog predloga, moram da priznam da ne znam tacno kako bih izveo to patch-ovanje: gde, sta u Builderu (ili kodu) da ukucam (i meni je dosadio taj DOS prozor)/imam Borland 6.0 Enterprise Suite/. (Pored toga ne razumem bas ni kod koji si mi dao. - ali to sad nije bitno). Ili je mozda pametnije da tu mikrohirurgiju ostavim za kasnije.

I na kraju, verovatno ste prevideli ono pitanje o default-u iz switch strukture.


Besten Dank
[ Reljam @ 22.08.2003. 20:51 ] @
Citat:
Dragi Tata:
Žao mi je gospodo, ali nije u pitanju "stvar ukusa" i "šta je lepše", već je jednostavna činjenica da pametna upotreba funkcija ne - članica unapređuje dizajn.
Verovatno nisam dobro shvatio to na sta si mislio, ali ne vidim zasto je to "jednostavna cinjenica" - zbog cega je to bolje od onog drugog? Koji su (nesubjektivni) argumenti?
[ Dragi Tata @ 22.08.2003. 20:57 ] @
Nesubjektivni argumenti:

1) Bolja enkapsulacija

2) "Loose object coupling"

[ Reljam @ 22.08.2003. 22:08 ] @
Nemanja, izgleda da cemo morati da se "dogovorno ne slozimo". Po meni nasilno cupanje metoda samo zato sto ih je moguce implementirati bez pristupa privatnim clanovima nije dovoljan razlog za to da objekti i njegovi metodi ne budu nikako povezano. Ne mislim da je enkapsulacija bolja na taj nacin. Kad smo vec kod toga, mislim da postoji dobra i losa enkapsulacija, ali o tome drugi put.

Loose-coupling: kao i u svemu ostalom, potrebna je mera. Ne mislim da u Triangle treba trpati sve pa i D3D9Draw, osim ako se Triangle klasa ne koristi bas za tu svrhu. Ali takodje ne mislim da iz te klase treba sve pocupati - to je drugi esktrem, i tu se smanjuje prakticna vrednost te klase. Jer ako dovoljno temeljno primenimo onaj algoritam od malopre koji si spomenuo, dobicemo jedan fin skup proceduralnih APIja koji barataju svacime... Ni to nije ideja.

Moje vidjenje je da su odluke ovog tipa stvarno stvar ukusa i da ne postoji univerzalno resenje. Sve zavisi od konkretnog problema koji se resava i malo inzinjerske sposobnosti da se odredjena teoretska pravila ne prate do ekstrema. Otprilike kao sto apsolutna normalizacija baze podataka nije uvek najbolje resenje, isto tako i ovo ovde.

U svakom slucaju, let's agree to disagree.

Pozdrav,
Relja
[ Dragi Tata @ 22.08.2003. 22:36 ] @
Izvini Relja, ali od dogovora nema ništa. Uopšte nisam spreman da prihvatim da je to stvar ukusa.

Citat:
Po meni nasilno cupanje metoda samo zato sto ih je moguce implementirati bez pristupa privatnim clanovima nije dovoljan razlog za to da objekti i njegovi metodi ne budu nikako povezano.


Polazimo od različitih stanovišta: ti govoriš o "nasilnom čupanju metoda iz klase", a ja govorim o "nasilnom trpanju funkcija u klasu". A objekti i njihovi metodi su naravno povezani i ako metodi nisu članovi klase. Pogledaj onaj Sutter-ov članak na koji sam ostavio link.

Citat:
Ne mislim da je enkapsulacija bolja na taj nacin


Samo mi reci jesi li pročitao Meyers-ov članak? Čovek dokazuje da enkapsulacija jeste bolja na taj način. Uostalom, meni je sasvim očigledno da je enkapsulacija bolja kad nemaš pristup privatnom delu klase. Ne razumem na osnovu čega možeš da tvrdiš suprotno.

Citat:
Loose-coupling: kao i u svemu ostalom, potrebna je mera. Ne mislim da u Triangle treba trpati sve pa i D3D9Draw, osim ako se Triangle klasa ne koristi bas za tu svrhu. Ali takodje ne mislim da iz te klase treba sve pocupati - to je drugi esktrem


Naravno, tu možemo da se složimo. Ali ako pogledaš malo bolje, cela priča je počela kada se Filip prenerazio što vidi funkcije ne-članice u C++u. Niko ne kaže (čak ni Meyers) da sve funkcije treba da budu ne-članice (onda se vraćamo na proceduralno programiranje). Ali treba koristiti ne-članice mnogo češće nego što to čini većina programera. U suprotnom dobijemo klase kao što je ova:

http://msdn.microsoft.com/libr...ml/_mfc_cwnd_class_members.asp
[ caboom @ 23.08.2003. 01:00 ] @
Citat:
Dragi Tata:
Naravno, tu možemo da se složimo. Ali ako pogledaš malo bolje, cela priča je počela kada se Filip prenerazio što vidi funkcije ne-članice u C++u. Niko ne kaže (čak ni Meyers) da sve funkcije treba da budu ne-članice (onda se vraćamo na proceduralno programiranje). Ali treba koristiti ne-članice mnogo češće nego što to čini većina programera. U suprotnom dobijemo klase kao što je ova:

http://msdn.microsoft.com/libr...ml/_mfc_cwnd_class_members.asp


... ili dobijes nesto kao cocoa framework koja sa objective c-om daje skoro neprirodan nivo apstrakcije koji te na trenutke vodi do apsurdnog i ponekada tesko uhvatljivog koda . meni je licno kalemljenje objektnog modela u/na c (da li kroz c++ ili objective c) prilicno nasilje, ali to je postao industrijski standard kao i mnogo drugih stvari. OO implementacija nad jezikom koji nije za to podesan ni u kojem slucaju ne moze biti elegantno resenje i uvek vodi do mnogo izuzetaka, kao sto je i ovde slucaj.
[ brcha @ 23.08.2003. 03:17 ] @
Kako nije stvar ukusa? Naravno da ne treba preterivati... Preterano nasledjivanje (posebno multiple inheritance) povecava kompleksnost programa i verovatno usporava njegovo izvrsavanje. U sustini OO programiranje omogucava programerima lakse programiranje, a ne korisnicima brze izvrsavanje, ali ipak treba imati meru u svemu. Isto tako, ako se program suvise oslanja na IDL objekte, to ce znacajno da uspori ceo program, ali ce, sa druge strane, program biti vise reusable. Izmedju te dve stvari treba naci sredinu, sto u sustini i nije stvar ukusa, nego vise nekog osecaja gde sta treba da se uradi. I suvise zavisi od sustine problema da bi moglo da se dokaze sta je bolje, a sta losije. Naravno da ne zelim nikoga da omalovazavam (niti imam pravo na to), ali sve teorije oko OO programiranja vise treba da budu vise neka okvirna uputstva nego striktno algoritamski definisana pravila. Sto kaze Morpheus u Matrix-u - I can only show you the door, but you must walk through it!

Kao primer lose objektne orjentisanosti moze da se uzme i Borlandova biblioteka OWL (nekadasnji pandan MFCu). Biblioteka je savrseno lepo organizovana, vrlo logicno razvijana, ali na kraju ispada suvise kompleksna da bi bila zgodna za upotrebu.

Isto tako, ne razumem zasto OO vezujete za jezik. Moze OO program da se pise i u asembleru. To je vise stvar pristupa problemu nego stvar jezika. Uostalom, secate li se biblioteke D-Flat pod DOSom (za pravljenje konzolnih aplikacija sa menijima, prozorima i sl) koja je bila potpuno OO u cistom C-u. A ne mozete da kazete da je C OO jezik!
[ brcha @ 23.08.2003. 03:28 ] @
Citat:
Pretender:
Sto se tice gornje problematike, nisam siguran da razumem kako f-ja pristupa SetSize(newWidht, newSize), moze da promeni objekat theRect (u kojem je deklarisana) ako je pozvana direktno iz main(), a ne moze ako je pozvala neka druga f-ja. After all, ona jeste f-ja pristupa tog objekta sta god da je pozove- ali ako se ovde radi o enkapsulaciji "na delu" OK, usvojicu to tako.


Stvar je u tome da druga funkcija ne barata sa objektom theRect nego sa njegovom kopijom! Sa druge strane, ako saljes pointer, saljes kopiju adrese na kojoj se nalazi theRect, ali na toj adresi se nalazi bas taj objekat, tako da njega mozes bez problema da menjas. A tu adresu ne mozes (niti imas potrebu) da menjas. Reference su noviji tip podataka koji je neka vrsta transparentnog pointera, odn. ne moras da se bavis sa pointerima, nego baratas sa normalnim objektom. Shvatices kad procitas ta sledeca poglavlja.

Citat:

U vezi brchinog dobronamernog predloga, moram da priznam da ne znam tacno kako bih izveo to patch-ovanje: gde, sta u Builderu (ili kodu) da ukucam (i meni je dosadio taj DOS prozor)/imam Borland 6.0 Enterprise Suite/. (Pored toga ne razumem bas ni kod koji si mi dao. - ali to sad nije bitno). Ili je mozda pametnije da tu mikrohirurgiju ostavim za kasnije.


Zaboravi na to. To je ulazni kod za UNIX alatku patch. Nisam siguran da postoji na windowsu osim u okviru cygwin (ili nekog slicnog) okruzenja.

Citat:

I na kraju, verovatno ste prevideli ono pitanje o default-u iz switch strukture.


Pa cini mi se da nikad nece doci do tog koda. Moze da se izbaci ili taj default ili onaj if pre switcha.
[ Dragi Tata @ 23.08.2003. 05:19 ] @
Dobro, kad smo se složili da treba odlučivati od slučaja do slučaja, da se vratimo na izvorni problem. Zašto mislite da funkcija DoDrawRect treba da bude članica klase? Šta bi se time konkretno doblo, ukusi na stranu. Što se mene tiče, ja bih samo promenio deklaraciju da bude

Code:

void DoDrawRect(const Rectangle& theRect)


Beneficija: mala dobit u performansama (nema kopiranja objekta).
[ brcha @ 23.08.2003. 11:26 ] @
Apsolutno nema nikakve razlike da li se koristi referenca ili se poziva funkcija clanica. Jedino sto bi se funkcijom clanicom dobilo su dve ret instrukcije manje i par push instrukcija manje, odn. ne bi se pozivale funkcije theRect.GetHeight() i .GetWidth() nego bi se direktno koristile privatne promenljive itsWidth i itsHeight, a to i nije neka razlika. Mada to isto moze da se postigne i deklarisanjem funkcije DoDrawRect(const Rectangle& theRect) kao prijateljsku (friend) funkciju klase. Dakle, sustinsku razliku ja ne vidim.

Razlika moze da postoji ako bi Rectangle imao apstraktnu funkciju Draw, pa da se posle nasledi u ConsoleRectangle, BGIRectangle, OpenGLRectangle, GTKRectangle i slicno. U takvom slucaju se razlika u kodu pravi samo u deklaraciji promenljive, a uvek se iscrtava sa theRect.Draw() (odn, onda bi trebalo dinamicki alocirati tu promenljivu sa new kao odgovarajuci ...Rectangle, ali necu sad da komplikujem celu pricu).
[ leka @ 23.08.2003. 12:22 ] @
Ja se slazem sa Reljam-om ovaj put. Stvar je ukusa programera sta ce i kako ce da koristi. Nemanja ce verujem da uleti sa pricom o dobroj/losoj programerskoj praksi... A meni ce CUJ i CodeProject da pokazu sta je dobra programerska praksa? - Nesto nisam bas ubedjen u to...
[ leka @ 23.08.2003. 12:24 ] @
Citat:
Dragi Tata:
Code:

void DoDrawRect(const Rectangle& theRect);


Beneficija: mala dobit u performansama (nema kopiranja objekta).


Naravno, ko god je malo ozbiljnije kodirao u C++-u ce tu funkciju tako napisati... Tacnije, ko zeli da programira na malo visem nivou. Nista ne bih imao protiv da se prosledi pokazivac na objekat!
[ filmil @ 23.08.2003. 13:41 ] @
Citat:
Dragi Tata:
Zašto mislite da funkcija DoDrawRect treba da bude članica klase?


Sad, pošto su drugi odradili advocacy :) mogu da nastavim da se ježim na knjigu iz edicije * za 21 dan (* ovde čitati kao bilo šta, pa i c++ :) ). DoDrawRect treba da bude članica _neke_ klase koja se bavi crtanjem, dakle ne nužno klase Rectangle, recimo pod firmom da se onda Rectangle može tumačiti na različite načine: kao skup tačaka koje treba spojiti pravim linijama ili kako skup tačaka koje treba koristiti kao vođice za neki spline ili šta već.

Da odgovorim na tvoje pitanje drugim pitanjem: zašto je u datom kodu DoDrawRect van klase, a recimo DrawShape unutar klase? Zašto je odabrao prenošenje po vrednosti sa kopiranjem objekta kada to nije dobar način da se objekat prenese? Zašto je postavio nepostojeću default granu u onaj switch? Da li je napomenuo koji su mogući problemi pri tome?

Čini mi se da je autor proizvoljno rascepkao kod kako bi pokazao nekoliko koncepata; pritom je međutim ilustrovao i par čudnih odluka u vezi sa dizajnom koda. Posmatram i u svetlu onog prethodnog jako čudnog koda sa pamćenjem koordinata, gde ne samo što duplira podatke već i dizajnom klase dozvoljava korisniku da duple podatke izvede iz sinhronizma.

Ako se sećate, pamćene su i koordinate gornje leve i donje desne tačke, kao i četiri vrednosti za krajnje koordinate -- što je prosto suvišno u tom primeru -- a još je dozvolio da se svaka od tih 6 vrednosti posebno zadaje tako da ja mogu, namerno ili nenamerno, da postavim vrednosti koje će mi dati nepostojeći pravougaonik -- a to dobar dizajn nikada neće dozvoliti. Sad, to sa dupliranjem podataka može da bude korisno u slučajevima kada želimo da amortizujemo troškove nekog računanja, recimo kada pri push-u uvećamo brojač elemenata na steku iako se broj elemenata uvek može sračunati prolaskom kroz kontejner koji ga implementira, ali dozvoliti da ispravnom upotrebom objekat može da dođe u neispravno stanje, to već nije kako treba.

Zaključak je da primere iz knjige verovatno treba uzimati sa zrnom soli -- ili da treba promeniti knjigu.

f
[ brcha @ 23.08.2003. 14:29 ] @
Dobro sad, pass by value je tu verovatno zato sto su tek u sledecem poglavlju pokazivaci. Pretpostavljam da ce posle da se vrati na primer i da kaze da je bolje sa pokazivacima i da ce na kraju da predje na reference. Odn. nadam se da je tako.

A ova default grana je svakako glupost koju je autor ocigledno prevideo. Mozda je pisao knjigu 21 dan ;)

Citat:

Posmatram i u svetlu onog prethodnog jako čudnog koda sa pamćenjem koordinata, gde ne samo što duplira podatke već i dizajnom klase dozvoljava korisniku da duple podatke izvede iz sinhronizma.


Da, secam se tog primera. I to je bilo iz C++ za 21 dan?

F
[ Pretender @ 23.08.2003. 15:49 ] @
Sve sto je receno (meni; a i dosta ostalog) je understood.

Hvala brchi i filmilu (ali i ostalim ucesnicima u diskusiji, jer su se mogli cuti razliciti, zanimljivi stavovi).

Sto se tice kvaliteta knjige; i sam sam malo ustuknuo pred njenim naslovom prilikom kupovine (delim filmilovo misljenje o takvim naslovima), ali sam je na kraju (paradoxalno) verovatno zbog njega i kupio, ocekujuci da cu tako u razmerno kratkom roku ovladati nekim bazicnim konceptima C++ i OO, obzirom da ne nameravam da se na tome zaustavim.

Kakva je da je, sad sa pola puta nema nazad. Uostalom to je jedna od samo 2 (opseznije) prevedene knjige koje su na raspolaganju. (Mislim da je na pocetnickom nivou (gde je za razumevanje osnovnih koncepata vazan svaki zarez), bolje da knjiga bude prevedena, osim ako se pocetnik ne sluzi engleskim jezikom kao maternjim.)

However, nadam se da ce posluziti za upoznavanje sa C++ i OO, a za posle cemo da vidimo.
Postoji pri tom (ocigledno) i opasnost pogresnog usmerenja, ali tu se eto uzdam u Vase sugestije, koje su mi i do sada bile od velike pomoci.


Pozdrav
[ Dragi Tata @ 23.08.2003. 18:50 ] @
Elem, nisam znao da su Scott Meyers i Herb Sutter nikakvi autoriteti za programera kao što je Leka. Moraćemo da predložimo Bjarnetu da ih izbaci iz komisije za standardizaciju C++a i da umesto njih ubaci Leku :)

Uglavnom, poenta je sledeća: za razliku od nekih drugih programskih jezika, u C++u nije obavezno, pa čak ni poželjno trpati svu funkcionalnost u klase. Postoje neka "kruta pravila":

- virtuelne funkcije su uvek članice
- unarni operatori su uvek članovi
- binarni operatori ne treba nikad da budu članovi (mada sintaksa to omogućava)
- funkcije kojima je neophodan pristup podacima članicama (očigledno) moraju da budu članice.

Van toga, sve je stvar procene (ne "ukusa"). Šta vodi kodu koji je lakši za održavanje, proširivanje, razumevanje?

Recimo, ako se javi potreba da uvedemo neku operaciju nad objektima klasa A i B. Da li ćemo tu operaciju staviti u klasu A, u klasu B, da li ćemo napraviti neku treću klasu (medijator) C ili ćemo jednostavno da napišemo funkciju ne-članicu? Zavisi od procene i konkretnih okolnosti. Ali ne od ukusa. Pitanje ukusa je npr, gde stavljate vitičaste zagrade i da li koristite tabove ili spejsove za identaciju. Odluka da li se neka operacija implementira kao članica ili ne može imati posledice na kvalitet dizajna, a samim tim i na troškove proširivanja/menjanja/održavanja koda, a to više nije stvar "ukusa".
[ Dragi Tata @ 23.08.2003. 18:58 ] @
Citat:
brcha:
Apsolutno nema nikakve razlike da li se koristi referenca ili se poziva funkcija clanica. ...


Da ne bismo skretali priču na optimizaciju, samo da napomenem da sam performanse pomenuo u kontekstu slučajeva kad je funkcija ne-članica (prosleđivanje po vrednosti vs po referenci), a da nisam uopšte razmatrao slučaj kad je funkcija članica.
[ Dragi Tata @ 23.08.2003. 19:04 ] @
Citat:
filmil:

Da odgovorim na tvoje pitanje drugim pitanjem: zašto je u datom kodu DoDrawRect van klase, a recimo DrawShape unutar klase? Zašto je odabrao prenošenje po vrednosti sa kopiranjem objekta kada to nije dobar način da se objekat prenese? Zašto je postavio nepostojeću default granu u onaj switch? Da li je napomenuo koji su mogući problemi pri tome?



Ako želiš da kažeš da je primer fundamentalno loše odrađen, tu ćemo da se složimo. Rasprava je samo oko toga da li bi guranje te funkcije u (bilo koju) klasu unapredilo dizajn.
[ brcha @ 23.08.2003. 19:09 ] @
Citat:
Dragi Tata:
- virtuelne funkcije su uvek članice
- unarni operatori su uvek članovi
- binarni operatori ne treba nikad da budu članovi (mada sintaksa to omogućava)
- funkcije kojima je neophodan pristup podacima članicama (očigledno) moraju da budu članice.

Van toga, sve je stvar procene (ne "ukusa"). Šta vodi kodu koji je lakši za održavanje, proširivanje, razumevanje?


Ok, slazem se, "ukus" je malo glupa rec. Ja sam pod "ukusom" i "osecajem" podrazumevao procenu.

Sto se tice binarnih operatora, oni se mnogo logicnije i lepse pisu kao friend funkcije nego kao clanice. Usput, slazem se sa pravilima.
[ brcha @ 23.08.2003. 19:10 ] @
Citat:
Dragi Tata:
Citat:
brcha:
Apsolutno nema nikakve razlike da li se koristi referenca ili se poziva funkcija clanica. ...


Da ne bismo skretali priču na optimizaciju, samo da napomenem da sam performanse pomenuo u kontekstu slučajeva kad je funkcija ne-članica (prosleđivanje po vrednosti vs po referenci), a da nisam uopšte razmatrao slučaj kad je funkcija članica.


Ok, jasno je da pass by value ovde ne valja. A i ona moja "optimizacija" nema bas mnogo smisla jer par clktckova vise ili manje ne cini prolece
[ filmil @ 23.08.2003. 19:18 ] @
Citat:
brcha:
Ok, slazem se, "ukus" je malo glupa rec. Ja sam pod "ukusom" i "osecajem" podrazumevao procenu.


Interesantno je da upravo čika Bjarne govori o dizajnu programa koristeći iste termine: practice, patience, taste. Ne bih baš da se zaletim u parafraziranju, ali ono čega se sećam (i ako ima interesovanja pokušaću da pronađem i iscitiram) da je o dizajnu programa govorio u krajnje subjektivnim kategorijama poput gore pomenutih.

f
[ brcha @ 23.08.2003. 19:29 ] @
Citat:
filmil:
Interesantno je da upravo čika Bjarne govori o dizajnu programa koristeći iste termine: practice, patience, taste. Ne bih baš da se zaletim u parafraziranju, ali ono čega se sećam (i ako ima interesovanja pokušaću da pronađem i iscitiram) da je o dizajnu programa govorio u krajnje subjektivnim kategorijama poput gore pomenutih.


Da, ali rec "ukus" moze pogresno da se shvati. A ta procena ne moze da bude nesubjektivna jer ne moze da postoji tacan algoritam procenjivanja. Odnosno, procena je stvar znanja, iskustva, osecaja i ukusa.

Ajde, ako nadjes link, posalji ga.
[ filmil @ 23.08.2003. 19:51 ] @
Citat:
brcha:
Ajde, ako nadjes link, posalji ga.


U pitanju je odlomak knjige C++ programming language, tako da ću morati da sačekam da se otvori biblioteka... :)

f
[ Dragi Tata @ 23.08.2003. 19:55 ] @
Hajde da odstupim još mao pa da dopustim da u nekim slučajevima izbor dizajna može i da bude stvar ukusa. Međutim, ako zbog "ukusa" dobijemo klase kao što je gorepomenuta CWnd, onda smo napravili grešku koja može da košta $$$$, a onda možemo da popijemo otkaz i onda se priča o ukusu završava.

Uglavnom, nadam se da više niko ne smatra da su funkcije ne-članice apriori greška u dizajnu.
[ leka @ 24.08.2003. 15:59 ] @
Citat:
Dragi Tata:
Elem, nisam znao da su Scott Meyers i Herb Sutter nikakvi autoriteti za programera kao što je Leka. Moraćemo da predložimo Bjarnetu da ih izbaci iz komisije za standardizaciju C++a i da umesto njih ubaci Leku :)


Nemanja, shvati da se prosto nasa misljenja ne poklapaju i zivi sa tim. :) Smatram da je "dobra programerska" praksa individualna stvar, za razliku od tebe i tebi slicnih koji mislite da ce Vas neke "face" nauciti dobroj programerskoj praksi.

Zasto mislim da je programerska praksa individualna stvar? - Zato jer programer u svom zivotu moze da radi na razlicitim tipovima projekata. Programer koji celog zivota radi biznis aplikacije ce raditi prema dobro definisanim sablonima. Programer koji mora da radi na malo visem nivou, a licno je programer nizeg nivoa ce u nekim svojim projektima koji su po pravilu nizeg nivoa da koristi raznorazne precice, cake kojih se C++ programeri klone, a samim tim ih kasnije cak i ne "kapiraju". Nije ni cudo da nekad naidjem na C++ programera koji se totalno izgubi u C++ kodu koji je napisao C programer. I ko ce meni da da za pravo kada kazem "e to ne treba da se radi tako, vec to uradi ovako?" ? Ja prosto smatram da cak ni Bjarne nema, niti sme da ima, tu moc. - Dok kod radi posao za koji je napisan, sve je okej.

Znam, znam, pocece se prica o tome "a koliko vremena treba nekom drugom programeru koji slucajno treba da nastavi tu gde je prethodni stao?"... Za razliku od drugih kojima ovo mozda ne pada na pamet, ja bih rekao prosto da taj drugi programer nije dostigao nivo prvog programera - jer razmislja sablonski. Cak stavise, otisao bih u krajnost i rekao da su takvi programeri malo "brainwashed"...
[ Dragi Tata @ 24.08.2003. 17:56 ] @
Lepo, svi imamo svoje mišljenje.

Setih se jedne izreke koja u prevodu glasi "Razlika između Boga i C++ programera je ta što Bog zna da nije C++ programer" :)
[ sspasic @ 24.08.2003. 21:13 ] @
Nisam mogao da odolim

Citat:

This joke was told at a Yourdon seminar by Julian L. Morgan.

Question: What is the difference between an object methodologist and a terrorist?
Answer: You can negotiate with the terrorist.

[ brcha @ 25.08.2003. 04:22 ] @
Citat:
leka:
Znam, znam, pocece se prica o tome "a koliko vremena treba nekom drugom programeru koji slucajno treba da nastavi tu gde je prethodni stao?"... Za razliku od drugih kojima ovo mozda ne pada na pamet, ja bih rekao prosto da taj drugi programer nije dostigao nivo prvog programera - jer razmislja sablonski. Cak stavise, otisao bih u krajnost i rekao da su takvi programeri malo "brainwashed"...


Leko, ne mogu da se složim sa tobom. Da bih ja koristio Qt, ne moram da radim u Trolltech-u, već samo moram da znam kako da ga iskoristim za svoje potrebe. Znači, uopšte ne zalazim u to koliko ja (ili bilo ko drugi) znam o C-u i C++-u ili o bilo kom jeziku, već pričam samo o tom nastavljanju programiranja. Jedna od, po meni, najznačajnijih karakteristika OO programiranja je to što mogu i moram objekat da gledam kao BlackBox. Odn. uopšte me ne zanima šta se dešava u objektu, dokle god on putem svojih metoda izvršava ono što mu je rečeno. To omogućava da bez ikakvog znanja o strukturi neke biblioteke mogu da je iskoristim. Ne kažem da poznavanje unutrašnje strukture objekata škodi, ali ne sme da bude presudno u korišćenju objekta. Ovo sve se ne odnosi samo na OO programiranje, nego na mnogo još štošta iz realnog sveta!

Pozdrav
F
[ filmil @ 27.08.2003. 11:47 ] @

Citat:

[ ... ] there can be no cookbook method for creating good software. Detailed "how-to" descriptions can exist for specific well-understood kinds of applications but not for more general application areas. There is no substitute for intelligence, experience and taste in programming.


Bjarne Stroustrup, "The C++ Programming language", second edition, pp 362, section 11.1, Addison-Wesley Longman, ISBN 0-201-53992-6
[ Reljam @ 28.08.2003. 18:33 ] @
I na kraju se vracamo na ono sto pricam od pocetka, a to je da je dizajn programa in the real world jedna neegzaktna i subjektivna stvar. Neke opste principe je naravno moguce formalizovati, ali na kraju sve je to stvar ukusa, koji se izmedju ostalog formira i iskustvom.
[ Dragi Tata @ 28.08.2003. 19:54 ] @
Opet se ne slažem. Kvalitet dizajna se da lako "izmeriti" količinom vremena (novca) potrošenim za održavanje (proširivanje) sistema. Prošle godine sam imao prilike da krpim neki RPC sistem koji je naš tadašnji "guru" (otpušten u međuvremenu) sklepao - otišlo je skoro pola godine dok ga nisam očistio od bagova. Tip je koristio gomilu nekih globalnih promenljivih u višenitnom okruženju - recept za propast. Da je malo manje sledio svoj ukus, a više čitao o dizajnu višenitnih aplikacija, nikad ne bismo došli u tu situaciju.

Programiranje (u širem smislu te reči) nije umetnost, već inženjerska disciplina kao i svaka druga.
[ brcha @ 28.08.2003. 20:35 ] @
Citat:
Reljam:
I na kraju se vracamo na ono sto pricam od pocetka, a to je da je dizajn programa in the real world jedna neegzaktna i subjektivna stvar. Neke opste principe je naravno moguce formalizovati, ali na kraju sve je to stvar ukusa, koji se izmedju ostalog formira i iskustvom.


Ne baš toliko neegzaktna i subjektivna stvar! Postoje mnogi principi kojih bi se trebalo držati. Kao što je spomenuo Nemanja, pravljenje programa u multithreaded okruženju sa globalnim promenljivama svakako nije baš najbolja ideja (globalne promenljive su često izvor grešaka i u "običnim" singlethread programima, a kamoli kad funkcije treba da budu reentrant i slično).

Ako je reč o objektnom programiranju, onda bi trebalo da se prvo ceo program pažljivo isplanira i razdeli na manje celine, uz mogućnost lakog proširivanja i dodavanja novih funkcionalnosti. A to nije baš samo stvar ukusa, već mnogo više stvar detaljnog planiranja i analize problema. Ovaj deo pravljenja programa je možda i značajniji od kasnijeg kodiranja klasa i funkcija i nikako ne sme da bude potcenjen!

Stvar je u tome da ne postoji neko generalno pravilo da li je bolje da npr. funkcija bude članica klase ili da bude eksterna funkcija. To je stvar o kojoj se odlučuje u trenutnoj situaciji u skladu sa tim šta radi ta funkcija, da li je potrebno da kasnije bude nasleđena ili je recimo bolje da transparentno barata i sa baznim i sa nasleđenim klasama. Naravno da u svemu tome do neke mere učestvuje i ukus, ali nije presudan.

U slučaju crtanja onog pravougaonika, moje je mišljenje bilo da funkcija treba da bude interna i to moje mišljenje je bazirano na nekom mom zamišljenom modelu aplikacije u okviru koje se javlja ta klasa. Ali pravo mišljenje o tome da li treba da bude interna, eksterna ili možda članica neke druge klase (tipa bool Display::drawRectangle(Rectangle& theRect);) je stvar dizajna celokupne aplikacije i ne može da se gleda samo za ovako istrgnut primer.

PS: intelligence, experience and taste