Jump to content

návod Úvod do OOP #1


HighPrint

Recommended Posts

  • Hlavní moderátor

Toto by klidně mohlo sloužit jako vzor pro ostatní návody. Pěkná práce. Takovéto tuty jsou celkem zásadní, každý se dříve nebo později s OOP setká, takže určitě je dobré mít základní znalosti.

Link to comment
Share on other sites

  • 3 weeks later...

Určitě je to + pro lidi, kteří začínají v C++ a je to i přehledné ;) Ale mnohem efektivnější by to bylo ukázat třeba v C# nebo Javě, ve kterým (a to hlavně v Javě) je všechno objekt a striktně se řídí OOP. Myslim si, že některý lidi to může rozhodit, protože syntax je v C++ jiná a to hlavně v pohledu interface, který se řeší úplně jinak, než v jiných jazykách. Ale to neber jako kritiku, spíše takový hint a možná, by to bylo dobré napsat i do titulku ;)

 

A teď nějaké mé postřehy, co jsem v rychlosti zahlédl.

1) jako přiklad uvádíš třídu Osoba, což proti tomu nic nemám, spíš mě vyděsily ty datové typy proměnných (sice to s OOP nemá nic společného, ale když už, tak ať to dává aspoň smysl)

enum Gender : unsigned {
   MALE,
   FEMALE
}

class Osoba {
private: // i když je private vychozí modifikátor, je dobré ho uvádět taky
   string name;
   unsigned age; // nevidim duvod pouzivat 4byte int, kdyz vek muzu ulozit do 1byte
   Genre gender; // pokud bude bool, tak false bude jako co? muz? O_o
}

2) init konstruktoru bez parametru je lepší zapisovat jako

Web() : traffic(50) {}

3) vytvoření instance Web se dělá 2 způsoby, né vždy je nutné alokovat třídu, pokud to není vyložené nutné, tak proč to dělat, potom je potřeba řešit uvolnění (většinou přes destruktor) a ještě tam máš chybu

// tohle tvoje prece nemuže fungovat
Web pawnocz = new Web(); /* alokace objektu Webu s názvem pawnocz */

// správně (nova instance "new" vraci pointer na alokovanou oblast v pameti)
Web* pawnocz = new Web();
pawnocz->IncreaseTraffic(); // volani

// nebo bez alokace a pristupovat přes "tecku"
Web pawnocz;
pawnocz.IncreaseTraffic(); // volani

4) tohle tvoje tvrzení "a to zbytečně vytváření setterů a getterů. Vytvoříme-li setter a getter pro privátní proměnnou, rovnou ji můžeme nechat zviditelnit celou." není pravda... Dost záleží na úhlu pohledu, díky tomu, že existuje getter/setter, tak je možné provést více operací než jen to volání/zápis... např. volat různé události, překreslení, nastavit další hodnoty, které uzce souvisí s nastavovanou apod. Vždy je dobré používat getter/setter i přesto, že jen nastavuji/ziskavaji hodnotu

 

5) co se týče destruktoru, tak je dobre se na ni nikdy nespolehat, vzdy je lepsi varianta udelat metodu, ktera vsechno uvolni a tu volat v destruktoru a idealne i na miste, kde uz s objektem nechce programator dale pracovat

 

6) a tohle tvrzení "Private je přístupná POUZE a JEN POUZE v dané třídě" také není pravda co se C++ týče... v C++ existují tzv. spřátelené třídy, ve kterých je možné volat i privátní fieldy mezi sebou.

 

7) v tom jednom příkladu nemáš konstruktor a destruktor public ;)

 

U toho tého "this" jsem skončil, moc dlouhý :))

Link to comment
Share on other sites

  • Globální moderátor

Diky moc, cenim si odpovedi a beru tvoje pripominky na vedomi. Jenom bych chtel dodat par komentaru k pripominkam. Snazil jsem se spise popsat princip oop a kvuli tomu se pak michaly ruzne syntaxe

 

1) jasne byl to jen priklad abych ukazal, ze trida muze bejt clenskou metodou jine tridy, nechtel jsem pouzit nic co by okolo toho nebylo nezbytne

 

2) dobra poznamka, v tu chvili me to nenapadlo, ale zase... snazil jsem se to brat co nejvic objektivne, takze initializer list nema treba zminovana java. A dale protoze se za tim skryva zajimavejsich veci at uz z praktickeho hlediska tak i teoretickeho

 

3) jo, tuto informaci bych mohl pripsat, co se tyce ty chyby tak jsem si ji vedom. Michal jsem blbe jazyky, tak se za to omlouvam, kazdopadne diky za bystre oko

 

4) pripisu informaci, az budu dostupnej na pc. Diky!

 

5) o tom jsem nikdy neslysel, mel jsem za to, ze destruktor je vzdy zaruceny. Mohl bys mi vic popsat proc se na nej nelze spolehnout?

 

6) pripisu jako poznamku pro c++

 

7) jsem si toho vedom, muj pokus o navod volit metodu "baby-steps" a postupne rozsirovat pojmy, proto jsem nechtel zatezovat na zacatku ctenare

Link to comment
Share on other sites

// správně (nova instance "new" vraci pointer na alokovanou oblast v pameti)
Web* pawnocz = new Web();
pawnocz->IncreaseTraffic(); // volani

// nebo bez alokace a pristupovat přes "tecku"
Web pawnocz;
pawnocz.IncreaseTraffic(); // volani

4) tohle tvoje tvrzení "a to zbytečně vytváření setterů a getterů. Vytvoříme-li setter a getter pro privátní proměnnou, rovnou ji můžeme nechat zviditelnit celou." není pravda... Dost záleží na úhlu pohledu, díky tomu, že existuje getter/setter, tak je možné provést více operací než jen to volání/zápis... např. volat různé události, překreslení, nastavit další hodnoty, které uzce souvisí s nastavovanou apod. Vždy je dobré používat getter/setter i přesto, že jen nastavuji/ziskavaji hodnotu

 

5) co se týče destruktoru, tak je dobre se na ni nikdy nespolehat, vzdy je lepsi varianta udelat metodu, ktera vsechno uvolni a tu volat v destruktoru a idealne i na miste, kde uz s objektem nechce programator dale pracovat

 

6) a tohle tvrzení "Private je přístupná POUZE a JEN POUZE v dané třídě" také není pravda co se C++ týče... v C++ existují tzv. spřátelené třídy, ve kterých je možné volat i privátní fieldy mezi sebou.

 

7) v tom jednom příkladu nemáš konstruktor a destruktor public icon_e_wink.gif

 

U toho tého "this" jsem skončil, moc dlouhý icon_e_smile.gif)

3.) vysvetlil si referencie v jednom riadku na ktore knihy davaju 20 stran...

4.) Suhlasim. Gettery a settery su spravne riesenie. V C++ zmenis switch pri kompilacii a vsetky volania sa zmenia na proste ziskanie hodnoty premennej. JVM to robi automaticky, C# by malo tiež.

5.) moz byt. Ale "Nikdy na ni nespolehat" je proti encapsulation. Nemal by si vediet jak su detaily implementovane a uz vobec nie clearovat objekty z inej triedy.

6.) NAvod je o OOP, nie o C++. V OOP teorii to plati. Inak v praxi mozes povedat ze nikde to nefunguje kvoli reflexii.

Jo a dobry navod, asi sa mi to nechcelo citat tak som ani nepisal. Vlastne ani teraz som to cele necital. :d

Jo a nemam co robit.

Link to comment
Share on other sites

5) o tom jsem nikdy neslysel, mel jsem za to, ze destruktor je vzdy zaruceny. Mohl bys mi vic popsat proc se na nej nelze spolehnout?

Jsem asi špatně napsal, destruktor by se měl vždy zavolat při zavolání delete, spíš jde o to, že při složitější implementaci je možné udělat virtuální destruktor a potom při vytvoření implementace nemusí být zcela jasné a může se i stát, že se nezavolá ten destruktor z implementace, ale z  rozhraní. Je to sice vic specifická záležitost, ale v C++ je to možný... ale pokud by se to stalo, tak to je většinou chyba samotné implementace, né jazyku, ale v jazycích, které mají vlastní GC, bych tomu neveřil, tam se ani nedoporučuje používat destruktor icon_e_smile.gif

 

 

 

6.) NAvod je o OOP, nie o C++. V OOP teorii to plati. Inak v praxi mozes povedat ze nikde to nefunguje kvoli reflexii.

Jasně, pokud se bavíme o OOP jako takovým tak máš pravdu, ale vzhledem k tomu, že je to spíš víc o C++ kde to OOP je trosku jiný a jinak se k nemu pristupuje, tak proto jsem i psal, ze je lepsi tenhle topic udelat jako OOP pro C++, aby ostatni vedeli jakou ma syntax v tomhle jazyku... idealni navod na OOP by byl v jave, ktera ho striktne dodrzuje uz od sameho pocatku, ale to uz jsem psal icon_e_smile.gif

Tak, mám chvíli čas, tak jsem se rozhodl dodělat ten zbytek icon_e_smile.gif

 

8) v tom zdrojáku pod "this" ti chybí návratové typy u 2 metod v deklaraci třídy

 

9) možná by bylo dobré zmínit, proč preferuješ a co to znamená to "m_" u instančních proměnych, ono je to dost různý, posledni dobou (pár let) spíš "frčí" samotné podtržítko v případě privátních členů.

Jinak opět zmíním, že to jde napsat i tímto stylem (to neber jako opravu, jen bych to zahrnul i do ukázky, protože jak jsem řekl, tak ukazovat OOP na C++ je trošku jiný než v jiných jazykách, kde je striktně daný zápis)

Web(int traffic, string url, string owner)
   : traffic(traffic), owner(owner), url(url) // vubec nevadi, ze nazev člena s parametrem je stejny, C++ si s tim poradi i bez "this"
{} 

10) Nechybi ti tady neco? icon_e_smile.gif

print pawnocz.getUrl() + " má " + pawnocz.getTraffic() + " návštěvnost."; /* pawno.cz má 50 návštěvnost */

11) U toho slova "static" mě zajímá, jak bylo myšleno tohle.. "Jediné plus je mají přístup k třídním proměnným a volat třídní metody", protože to není pravda, cokoliv je deklarovaný jako static, tak je úplně oddělený on instance třídy, tzn. jak metod, tak proměnných

 

Ten zbytek je relativně ok, jen bych asi zmínil věci ohledně polymorfismu, že tenhle řekneme zpusob vývoje větsinou pracuje s rozhraním a ne s abstraktnima tridama. V C++ jelikoz neni klicove slovo abstract nebo interface, tak se to zajistuje tak, ze jakmile ma trida aspon jednu metodu abstraktni (metoda = 0), tak se automaticky prevadi na abstraktni tridu. V pripade rozhrani je to tak, ze trida musi mit pouze public metody a vsechny abstraktni. Coz je neco, s cim tento tutorial nepocita a je to tez soucast OOP icon_e_smile.gif

 

A potom klicove slovo static je dobre pouzivat minimalne. Je dobre na metody napr. pro utilit tridy a tak, ale co se tyce statickych clenu tridy, tak opravdu zvazit, zda je nutne to delat jako staticky. Pri nevhodnem pouziti je to vic problemu nez uzitku a o bezpecnosti kodu ani nemluvim icon_e_smile.gif

 

V poslední řadě tady přikládám teda ukázku k předchozímu bodu 6. kde je mozne pristupovat k privatnim clenum (pouze C++), v jinych jazykach to mozne neni

#include <iostream> // pro cout

class B; // deklarace tridy pro pouziti ve tride A

class A {
private:
    int valueFromA;
public:
    A(int value) : valueFromA(value) {}
    void run(B ; // operace se tridou B ve tride A
};

class B {
friend class A; // umozni pristupovat tride A k privatnim clenum
private:
    int valueFromB;
public:
    B(int value) : valueFromB(value) {}
};

void A::run (B  {
    valueFromA = b.valueFromB; // b.valueFromB je private
    std::cout << valueFromA; // vypise 20
}

int main() {
    A a(10);
    B b(20);
    
    a.run(; // vypise 20
    
    return 0;
}
Edited by mimic
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...