Autor Wątek: [c++] Co lepsze? Menedżer, interfejs czy kilka obiektów tego samego typu?  (Przeczytany 11102 razy)

Offline Xirdus

  • Redaktor

# Marzec 28, 2014, 10:39:40
Xirdus: Można pisać w c++ strukturalnie... nie musisz od razu mu nakazywać używać "this".
Zamiast tworzyć wrapper na mapę czy vectora i wystawić jedną metodę lepiej jest tą metodę wystawić jako statyczną funkcję przyjmującą jako pierwszy argument tą kolekcje. Jest to praktyczniejsze...
Z tym że w czystym C jest łatwiej tego unikać. I przede wszystkim nie ma żadnej magii konstruktorów itp. - wszystko jest wołane explicite.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Xenox93

  • Użytkownik

# Marzec 28, 2014, 12:57:30
Hmm... ok, może macie rację, że lepiej stosować indeksy zamiast string'ów.

Cytuj
tablice będą lepsze wtedy gdy potrzebujesz iterować po tych krzesłach. Dla każdego innego przypadku te przecinki będą lepsze.
Zaciekawiło mnie to, a dokładnie, kiedy lub jaki jest ten inny przypadek? Podam to na przykładzie okien. Wiem, wiem, uparłem się na te okna, ale to dlatego, że chcę utworzyć "Framework" do ich tworzenia i obsługi, a dopiero, gdy w końcu nauczę się programować z głową, korzystać w 100% z obiektowego programowania, wezmę się za pisanie grafiki 2D, czyli tworzenie prostych gier platformowych oraz UI.

Otóż, chciałbym napisać uniwersalny kod, który będzie oferował tworzenie nawet 1k okien, do każdego z nich kilka callback'ów. Wykorzystam do tego celu kontenery STL oraz muszę zaprojektować jakąś klasę/przestrzeń nazw lub coś podobnego, co pozwoli mi na dodawanie, usuwanie itp. okien.

Cytuj
[...] wyszukiwanie obiektów po serializacji
Pierwszy raz spotykam się z takim terminem, więc byłbym wdzięczny podanie tego terminu na jakimś przykładzie.

Cytuj
PS: Nie rejestrujesz klasy okna dla każdego okna osobno... To raczej tam popracuj nad architekturą...
Na początku chcę skupić się na architekturze i jakimś logicznym zaprojektowaniu kodu. Zresztą w pseudokodach podałem jako komentarz, że w danym miejscu tworzona jest klasa okna. Jeśli znajduje się to w funkcji/metodzie - Create( ... ), oznacza to, że klasa jest tworzona za każdym razem, dla każdego okna.

Programowanie w C++, kojarzy mi się z użyciem cout, endl, a w klasach stosowanie hermetyzacji danych, czyli tworzenie metod i zmiennych prywatnych, publicznych i chronionych. Gdyż tego nie ma w C. Dodatkowo programowanie obiektowe kojarzy mi się z użyciem dziedziczenia, polimorfizm itd. itd.

PS. Nie ignoruję waszych komentarzy/propozycji, bo wszystkie biorę do siebie poważnie. Ale również chcę trzymać się swoich założeń, tworzyć wygodny, ludzki kod, bo w końcu język programowania służy do wydawania poleceń w sposób bliższy do naszego języka. Dlatego naukę programowania zaczyna się do Pascal'a. W ogóle nadal mam mętlik co do zaprojektowania kodu :/ A za cierpliwość i pomoc nadal dziękuję ;)

Offline ArekBal

  • Użytkownik

  • +1
# Marzec 28, 2014, 14:07:36
Cytuj
Zaciekawiło mnie to, a dokładnie, kiedy lub jaki jest ten inny przypadek?
Chociażby taki...
window0.setWidth(400)
window1.setWidth(256)
window2.setWidth(337)
zamiast wskazywać element tablicy, łapiesz za obiekt...

Cytuj
Pierwszy raz spotykam się z takim terminem, więc byłbym wdzięczny podanie tego terminu na jakimś przykładzie.
http://pl.wikipedia.org/wiki/Serializacja

No między innymi pobieranie danych z źródeł zewnętrznych(siakiś plik, internet) wymaga deserializacji. Na przykład czytasz xmla i tworzysz obiekt/y lub uzupełniasz właściwości obiektu na podstawie zawartości pliku.

Własne okno w WinAPI wymaga zarejestrowania tzw. "klasy"(w nomenklaturze WinAPI) okna, ale nie musisz i niepowinieneś rejestrować nowych klas per okno.

Posłuchaj "kolegów" z forum i popatrz na inne profesjonalne frameworki jak one to robią... zanim sam zabłądzisz... a z tego co piszesz wynika to już zabłądziłeś.

Offline Xenox93

  • Użytkownik

# Marzec 28, 2014, 16:18:39
Cytuj
Cytuj
Zaciekawiło mnie to, a dokładnie, kiedy lub jaki jest ten inny przypadek?
Chociażby taki...
window0.setWidth(400)
window1.setWidth(256)
window2.setWidth(337)
zamiast wskazywać element tablicy, łapiesz za obiekt...
No tak. Ale czy nie lepiej zawsze pisać w ten sposób?
Window windows;

windows.Get()[index].setWidth( ... );

// bądź

windows.Get()[nazwa].setWidth( ... );

lub

Window::SetWidth( windows[index] );

// bądź

Window::SetWidth( windows[nazwa] );

Cytuj
Własne okno w WinAPI wymaga zarejestrowania tzw. "klasy"(w nomenklaturze WinAPI) okna, ale nie musisz i niepowinieneś rejestrować nowych klas per okno.
Oczywiście, że o tym wiem ;) Dlatego w poprzednich projektach, klasy okna trzymałem w kontenerach STL, a następnie zanim dodałem/zarejestrowałem nową klasę, to sprawdziłem czy już wcześniej nie została dodana.

Cytuj
Posłuchaj "kolegów" z forum i popatrz na inne profesjonalne frameworki jak one to robią... zanim sam zabłądzisz... a z tego co piszesz wynika to już zabłądziłeś.
Już wcześniej korzystalem z innych Framework'ów, m.in. GLFW i Qt. Ten pierwszy tworzy okno, tylko do renderowania. Natomiast drugi jest nie intuicyjny, tysiąc klas, które dziedziczą po qtWidegt(?)( czy jakoś tak ). Fakt, faktem, że ten Qt jest już lepiej zbudowany niż taki WinAPI, ale nadal ma bolączki. Dodatkowo sprawa licencji. A nie wspomnę o tym, żeby zrozumieć kod lub napisać coś bardziej rozbudowanego, wcześniej trzeba poznać nie podstawy, ale zaawansowany C++( czyt. obiektowość, funkcje wirtualne itp. ). Ja zamierzam dać możliwość, ktoś może pisać "niskopoziomowo"(w przenośni) odnosząc się do poszczególnych funkcji danego API, "średnipoziomo" czyli już gotowe funkcje/metody, które np. pobierają rozmiar okna nie martwiąc się o to, którego API używamy oraz znając tylko podstawy C++ napisać aplikację, która będzie konkurowała z innymi poziomem graficznym( GUI, kontrolki ), a jedynie będą potrzebne zdolności do rozwiązania problemu - algorytmu, niżeli do rozmyślania nad sposobem tworzenia samego okna lub callback'ów

Ale prawda jest może bardziej gorzka i macie rację pisząc, że jest to gorszy pomysł. Jednakże od samego początku wydawał mi się łatwiejszy, daję możliwość wyboru sposobu programowania, w zależności od ambicji, a rezultat może być taki sam..

Offline ArekBal

  • Użytkownik

  • +1
# Marzec 28, 2014, 18:13:25
Cytuj
No tak. Ale czy nie lepiej zawsze pisać w ten sposób?

windows.Get()[nazwa].setWidth( ... );
JASNE ŻE NIE...

Z jakiego kontenera byś nie wybierał... zawsze lepiej wpierw wziąć referencje czy wskaźnik na ten obiekt, a potem ustawiać właściwości.
auto& window = windows.Get(nazwa);
window.setWidth( ... );
window.setHeight(...);
window.show();
Jasne... jedne kontenery będą przy braniu elementu szybsze niż inne(np. branie z tablicy po indeksie) ale trzymając się tej reguły masz wszędzie taki sam kod. I kod jest czytelniejszy. I obniżasz ryzyko literówek.


Podstawą c++ jest korzystanie z brzydkiego API kontenerów stl, a tego możesz wymagać od użytkownika.

Dam ci jeszcze jedną radę...
Na razie, nie pisz kodu dla innych. Staraj się pisać kod tak żebyś TY go teraz rozumiał i w przyszłości, żebyś mógł go pisać szybko i nie marnował czasu na duperelach. Ładne API to naprawdę drugorzędna sprawa i w najlepszych przykładach przychodzi naturalnie. Z potrzeby, a nie z widzimisię.

Offline Xenox93

  • Użytkownik

# Marzec 30, 2014, 18:05:44
1.
Cytuj
Z jakiego kontenera byś nie wybierał... zawsze lepiej wpierw wziąć referencje czy wskaźnik na ten obiekt, a potem ustawiać właściwości.
auto& window = windows.Get(nazwa);
window.setWidth( ... );
window.setHeight(...);
window.show();
Jasne... jedne kontenery będą przy braniu elementu szybsze niż inne(np. branie z tablicy po indeksie) ale trzymając się tej reguły masz wszędzie taki sam kod. I kod jest czytelniejszy. I obniżasz ryzyko literówek.
No tak, z referencji/wskaźników zawsze korzystam jak jest możliwość i wiem, że w danej funkcji/metodzie kilka razy będę się odwoływał do danego obiektu, zmiennej.

Hmm, sam nie wiem, może przeczytam jeszcze kilka artykułów lub w końcu napiszę jakiś kod i z czasem będę go ulepszał. Z pewnością chcę wykorzystać skrypty do tworzenia UI czy to w WinAPI/GDI czy w OGL'u. Tylko nie zrozumiecie mnie źle, nie chodzi mi o to, że chcę napisać całą aplikację w skrypcie, bo to jest niewydajne i nie poważne. Co najwyżej polecenia tworzące okno, kontrolki i callback'i do tych elementów.

2.
Cytuj
Dam ci jeszcze jedną radę...
Na razie, nie pisz kodu dla innych. Staraj się pisać kod tak żebyś TY go teraz rozumiał i w przyszłości, żebyś mógł go pisać szybko i nie marnował czasu na duperelach. Ładne API to naprawdę drugorzędna sprawa i w najlepszych przykładach przychodzi naturalnie. Z potrzeby, a nie z widzimisię.
Własnie o to mi chodzi. Zamierzam napisać framework( wiadomo, najpierw dla siebie, nawet teraz nie myślą o publikacji tego) z myślą, że pewnego dnia najdzie mnie ochota na programowanie czegoś. Wtedy wystarczy, że tylko dołączę framework do projektu, kilka poleceń/funkcji/metod i wszystko gotowe.

Zamiast skupiać się na algorytmie lub w najgorszym przypadku przypominać sobie, jak to się pisało w danym API( WinAPI, Qt, OGL'a itp. ), wywołuję tylko funkcje: Create, później funkcje dodające kontrolki, do tych kontrolek jakieś akcje( callback ), później tylko pętla i algorytm i program gotowy. Dodatkowo nie martwię się o pamiętanie jak korzystało się z API tworzącego okna na Windowsie a jak na Linuksie. To jest według mnie programowanie wydajne, efektywne i łatwe. Skrypty również mogą pozwolić mi na późniejsze edytowanie bez ciągłej kompilacji kodu. Chciałbym napisać taki framework, bo właśnie jest mi potrzebny, jak nigdy wcześniej.

PS. Jeszcze raz dzięki za rady i pomoc, bo pewne rzeczy sobie uświadomiłem i dały mi dużo do myślenia.

Edit:

3.

Cytuj
wyobrażasz sobie taki kod?
func_move(){
        manager.get("krzesło").move(10,15);
}

Bo ja raczej nie... A co powiesz o tym?

func_move( arg ){
        manager.get( arg.target ).move( arg.x, arg.y );
}
Ty piszesz o definiowaniu funkcji/metod, a ja o ogólnym zagadnieniu. Czyli o wywołaniu już ich, czyli miałem na myśli coś takiego:
int main()
{
     func_move( arguments{ object.Get( "krzesło"), 10, 20 } );

     // lub po głębszym zastanowieniu i to co każdy pisał, ma sens używanie indeksów, czyli:

    func_move( arguments{ objects.Get( 0 ), 10, 20 } ); // lub jeszcze inny sposób użycia indeksów, czy to, np. za pomocą operatora [] itp.

    // A w późniejszym stanie( zaawansowany poziom )

    func_move( arguments{ objects.Clicked(), 10, 20 } );
}

4.
Cytuj
class Window
{
         private:
            vector< WindowParam > windows;
Co to jest?? Obiekt okno który przechowuje okna (nazwa zmiennej)?
Proponuję Ci małe ćwiczenie - napisz cały kod strukturalnie. Serio! Napisz sobie "tworze_okno()", "usuwam_okno()" i tak dalej. Potem wywal wszystkie funkcje których nie używasz, pogrupuj tak żeby było wygodnie, i tak dalej... Potem, pod warunkiem że znasz zasady i cele programowania obiektowego, przełóż to na obiekty, może uda Ci się tu znaleźć nowy punkt widzenia
To jest rozwiązanie, gdzie trzymać zmienne, obiekty opisujące coś( w tym wypadku jest to opis okna ). Zamiast trzymać dane globalnie lub za każdym razem przenosić je i tym samym poprawiać kod, to używam klasy, które hermetyzują strukturę. A metody wykonują pewne operacje na nich. Swoją drogą nie jest to chyba taki zły pomysł. Ogólnie rzecz biorąc, nazwa klasy jest myląca, ale jak miałem ją nazwać? Pewnym rozwiązaniem jest utworzenie przestrzeni nazw i w niej trzymać kontener STL( strukturę ) oraz funkcje, które wykonują pewne operacje na tej zmiennej. Bo sam nie wiem w jakie logiczne miejsce przenieść te zmienne, utworzenie je globalnie to zły pomysł. Zresztą sam napisałeś, że zmienne globalne są antywzorcem:
Cytuj
Manie obiektów w jednym miejscu jest jednym z najgorszych antywzorców - bo takie coś najgorzej zmienić. Oczywiście czasem się przydaje, i sam często korzystam z globali - ale tylko i wyłącznie wtedy, kiedy niezbędne jest, by był do czegoś dostęp z dowolnego miejsca w kodzie. Jeśli tak nie jest, o wiele lepszym rozwiązaniem jest przekazywanie w konstruktorach poszczególnych klas referencji do wszystkich obiektów, które potrzebują.

5.
Cytuj
Protip: jeśli dobrze zaprojektowałeś swój framework i kod aplikacji z niego korzystający, to wcale nie będziesz musiał nigdzie z tych ID-ków korzystać - zwalczamy problem likwidując przyczynę, a nie skutki.
Dokładnie, po głębszym zastanowieniu stwierdziłem, że rzeczywiście wszyscy mieli rację, bo na ogół sprawdza się kolizję, na co wskazuje kursor i za pomocą tego, pobiera się elementy.

6.
Cytuj
Naucz się, w sensie krzeslo[100] zamiast krzeslo_1, krzeslo_2, ..., krzeslo_99. Poza tym, tablice wcale nie są takie nieprzydatne, nawet w świecie STL-a.
Ten przykład z n-tymi deklaracjami zmiennych, miał pokazać, jak kod się rozrasta z użyciem coraz większej ilości elementów. Fakt można użyć tablicy, ale tak jak już pisałem, chciałbym dynamicznie przydzielać pamięć( oszczędność ) oraz za pomocą skryptu, poza kodem C++. Więc do tego bardziej przyda się kontener STL.

7.
Cytuj
Cytuj
Gdybym miał zrobić tak jak piszecie, czyli nie tworzyć klasy Window, to kod w funkcji main wyglądałby strasznie, nawet z użyciem tablic lub samych kontenerów STL:
int main()
{
     vector<Window> windows( liczba_okien );

     for( int i = 0; i < liczba_okien; i++ )
    {
          // Rejestrowanie klasy okna dla każdego okna osobno
          [...]

          // Utworzenie okna
          [...]

          // Ustawienie każdego aktywnym itp.
          [...]
    }

    // Lub wersja hardcore

    // Rejestrowanie klasy okna dla każdego okna osobno
    [...]

    // Utworzenie okna
    [...]

    // Ustawienie każdego aktywnym itp.
    [...]

    // i tak n razy, co nie wygląda ładnie, przejrzyście i intuicyjnie :/
    // Lepiej byłoby zrobić coś takiego, Window to może być przestrzeń nazw( namespace ):
    Window::Create( WindowParams{ 800, 600, FULLSCREEN, ... } );
    Window::Create( WindowParams{ 320, 240, windowed, ... } );
    [...]

     return 0;
}
O ile rozwiązanie drugie jest do bani dla n > 3, o tyle pierwsze (z forem) jest jak najbardziej w porządku - pętla tworząca okna ręcznie jest funkcjonalnie identyczna z pętlą wywołującą funkcję. Oczywiście gdy nie jest to jedyne miejsce gdzie tworzy się okno, funkcja jest dużo, dużo praktyczniejsza i tylko idiota nie wydzieliłby tego - nawet gdy "niejedyne miejsce" oznacza dwa takie miejsca na całą bazę kodu. Jednak osobiście nawet przy jednym takim miejscu wydzieliłbym funkcję - bo tak mi się podoba.
Ja też miałem na myśli użycie tu funkcji, stąd na końcu dodałem użycie przestrzeni nazw:
// Lepiej byłoby zrobić coś takiego, Window to może być przestrzeń nazw( namespace ):
Window::Create( WindowParams{ 800, 600, FULLSCREEN, ... } );
Window::Create( WindowParams{ 320, 240, windowed, ... } );

Tak na prawdę, powyższy kod miał na celu podanie dowodu, że oddzielanie obiektów, zmiennych od metod, które wykonują na nich operacje jest bezsensu, gdyż pojawia się problem, gdzie zadeklarować zmienne itd. itd.
Dlatego zawsze tworzyłem klasy tego typu, np. dla okna:
class Okno // Pewnie użycie namespace Window - bardziej by pasowało, bo tworzenie funkcji globalnych na pewno jest pozbawione sensu
{
         private:
             vector<Struktura_opisująca_okno> okna; // Nazwa "okna" to uproszczenie, bo kontener przechowuje uchwyty i opisy okien

         public:
             // Konstruktory
             // Destruktor

             // Metody operujące na danych, np. Create

             // Metoda zwracająca referencję do kontenera przechowującego uchwyty i informacje o oknie
}
Zawsze to było dla mnie ułatwienie, bo nie musiałem martwić się o to, gdzie umieścić zmienną i funkcje, ostatecznie można byłoby zrobić to tak:
namespace Window
{
       vector<Struktura_opisująca_okno> okna;

       // Funkcje operujące na oknach, np. Create
};

lub

namespace Window
{
         // Same funkcje operujące na oknach, np. Create
};

int main()
{
     Window::Create( ... );
     [...]

     // Lub druga wersja
     vector<Struktura_opisująca_okno> okna; <- nie wiem, gdzie wtedy to umieścić.
                                                                            Czy użyć tego Manager'a, którego
                                                                            każdy mi odradzał? Ofc, nie upieram się,
                                                                            ale nie mam pomysłu, gdzie trzymać zmienne
                                                                            i inne, np. tekstury, shadery, obiekty 3D, materiały itp.
     Window::Create( okna, ... ); <- przekazuję referencję kontenera STL do funkcji, która operuje na danych
     [...]
}
Druga wersja chyba lepsza, bardziej logiczna i nie myląca.

PS. Myślałem, że tym razem wiadomość będzie krótka i zwięzła, ale okazało się że nie zauważyłem wcześniejszych komentarzy. Jednakże, mniej więcej wiem jak zaprojektować kod, tylko nie wiem czy nadal zmienną trzymać w przestrzeni nazw czy w jakimś innym miejscu.
« Ostatnia zmiana: Marzec 30, 2014, 18:58:39 wysłana przez Xenox93 »

Offline Xirdus

  • Redaktor

  • +1
# Marzec 30, 2014, 18:23:40
Tylko nie zrozumiecie mnie źle, nie chodzi mi o to, że chcę napisać całą aplikację w skrypcie, bo to jest niewydajne i nie poważne.
Powiedz to programistom Pythona ;)

Generalnie twój największy problem polega na tym, że bez głębszego obycia z programowaniem chcesz się brać za pisanie frameworka mającego programowanie usprawnić. Napisz sobie najpierw dwie, trzy średniej wielkości gry i wtedy myśl, jak to wszystko ładnie ogarnąć.

Offline ArekBal

  • Użytkownik

# Marzec 30, 2014, 19:03:29
Cytuj
Oczywiście, że o tym wiem ;) Dlatego w poprzednich projektach, klasy okna trzymałem w kontenerach STL, a następnie zanim dodałem/zarejestrowałem nową klasę, to sprawdziłem czy już wcześniej nie została dodana.
Opakować w obiekt(register w konstruktorze, unregister w destruktorze) i użyć jako statyczna funkcji. Tak wszystkie glew itp. ja inicjalizuję. Wygodniejsze niż trzymanie osobnej sekcji w mainie...

Offline lethern

  • Użytkownik

  • +1
# Marzec 30, 2014, 19:13:58
Cytuj
Zamiast skupiać się na algorytmie lub w najgorszym przypadku przypominać sobie, jak to się pisało w danym API( WinAPI, Qt, OGL'a itp. ), wywołuję tylko funkcje: Create

Trudno będzie mi się zgodzić.. myślę, że jest trochę inaczej - przecież wszystkie te frameworki mają funkcję create, która robiła by to samo co Twoja, z tym że.. u Ciebie ta create po prostu wywoływała by ich create.. Uprościłem, to istniejące API pozwala Ci konfigurować parametry itd., więc trzeba napisać trochę kodu żeby powiedzieć JAK ma się dziać, a Twój silnik mógłby mieć to już napisane (hardcoded).. no chyba, że chciałbyś trochę elastyczności, to wtedy to "create" zaczyna przyjmować parametry i ciągnie się... i zamiast jednej funkcji masz kilka, i tak dalej... aż tworzysz swoje własne Qt2 :) przecież te biblioteki powstały właśnie "bo WinApi to jest trudne, zróbmy coś swojego prostszego". Potem Ty tworzysz framework "bo tam jest biliard funkcji, zrobię coś prostszego", a potem za 5lat ktoś spojrzy na Twój kod i uzna, że "lepiej napiszę nakładkę na ten kod, taką prostszą"...

Cytuj
Dodatkowo nie martwię się o pamiętanie jak korzystało się z API tworzącego okna na Windowsie a jak na Linuksie.
Aha, zapomniałeś o jednej rzeczy. Ale to Ci wytłumaczę już powiedzeniem
Cytuj
Bardzo dobry programista pisze wyśmienity kod. Genialny programista używa kodu bardzo dobrych programistów


Cytuj
ewnym rozwiązaniem jest utworzenie przestrzeni nazw i w niej trzymać kontener STL
Dla mnie to jest to samo co zmienna globalna, wszystko (powiedzmy) ma do niej dostęp i nic za szczególnie nie kontroluje co się z tym dzieje
Cytuj
oraz funkcje, które wykonują pewne operacje na tej zmiennej.
Jeśli "funkcje" zamiast "metody"... To jest anty-programowanie obiektowe :)

Cytuj
Zresztą sam napisałeś, że zmienne globalne są antywzorcem
Co prawda nie ja jestem adresatem, ale mogę powiedzieć że... nie chodzi o to, że globale są antywzorcem, tylko DLACZEGO są... warto znać powody, bo jeśli ich nie znasz, to popełnisz te błędy nawet nie używając zmiennych globalnych. Powiem w skrócie, problem zmiennych globalnych jest taki, że DOWOLNE miejsce kodu jest potencjalnym miejscem błędu i wysypania się aplikacji, bo "5 miesięcy temu, w funkcji XYZ, założyłem że ta zmienna będzie taka, a okazało się teraz że coś w funkcji ABC zmieniłem i już jest siaka, błędu szukałem 3 dni i nocy" :)


Jeszcze na koniec: wydaje mi się, że lepiej niż pisać framework będzie jeśli napiszesz APLIKACJĘ, czyli funkcjonalności. Co prawda, łatwiej tu zrobić badziew, 5tysięczną funkcję main i tak dalej, ale jeśli się postarasz... Stwierdzasz sobie "chcę żeby było okno z 5 bryłami", więc tworzysz aplikację która to realizuje. I tutaj nadal będziesz miał managery, wzorce projektowania, i tak dalej.. I nadal wypada wszystko ładnie zaprojektować, z tą różnicą, że tu w pewnym momencie dojdziesz do wniosku, że "ta klasa jest słaba.. kurcze, chcę teraz zmienić coś i musiałbym wszystko napisać od nowa", i tu się uczysz. Pisząc framework, wydaje mi się, że jesteś bliżej świata, w którym "załóżmy że kwadrat jest kołem, więc zaprojektujmy tak i owak"
« Ostatnia zmiana: Marzec 30, 2014, 19:24:18 wysłana przez lethern »

Offline Xenox93

  • Użytkownik

# Marzec 30, 2014, 19:52:07
1.
Cytuj
Powiedz to programistom Pythona ;)
Fatk, faktem, że wydajność jest gorsza od C++, ale lepsza niż takiego Lua. W sumie sens pisania skryptów jest, ale w finalnym produkcie, powinien być parser(?), generator, który wszystko wygeneruje do języka C++ lub od razu Assembly z użyciem najnowszych instrukcji procesora, korzystając z 64-bit itp. Wtedy ostateczny produkt byłby szybszy i łatwiej by się go pisało ;)

Jednakże, skrypty mają jeden znaczący plus, przydają się do tworzenie aplikacji, gier itp. bo nie musisz co chwilę kompilować projektu. Tak samo programowanie AI powinno przebiegać, dopóki gra nie zostanie wypuszczona, zapisana jest w formie skryptu, ale jako finalny produkt została skompilowana lub wygenerowana do innego języka.

2.
Cytuj
Generalnie twój największy problem polega na tym, że bez głębszego obycia z programowaniem chcesz się brać za pisanie frameworka mającego programowanie usprawnić. Napisz sobie najpierw dwie, trzy średniej wielkości gry i wtedy myśl, jak to wszystko ładnie ogarnąć.
Też mi się czasami tak wydaje. Kiedyś napisałem najprostszą grę jaką można stworzyć, czyli kołko-krzyżyk. Najpierw w wersji CLI, a później za pomocą OGL'a. Ciężko było, bo właśnie pisałem kod w takiej formie, jakiej mi sugerujecie, czyli nie hermetyzowanie danych i umieszczanie zmiennych poza klasą.

Później chciałem napisać projekt, nie grę, ale korzystającą z OGL'a. Wtedy pojawiły się największe problemy, a tym samym nauczyłem się dużo. Gdy uporałem się z oknami, problemem było połączenie aplikacji ze skryptami. Gdy chciałem się poddać i zrezygnować z tego feature'a, nie wiedziałem jak napisać Callback'i bez nich.
Taka sytuacja, pętla ma miejsce cały czas, nie mogę ruszyć się z projektem dalej, bo zła architektura kodu, nie pozwala mi na postęp. Owszem mógłbym zrezygnować ze skryptów, pisać znowuż za pomocą GLFW, strukturalnie i tak jak piszecie, ale tym samym nie spełniłbym swoich założeń projektu, nie nauczyłbym się dobrego projektowania kodu. Wprowadzenie z powrotem użycia skryptu za jakiś czas byłoby nie możliwe, a tym samym projekt trafiłby do kosza lub zawieruszyłby się wśród innych plików. Wolę od samego początku poświęcić czas na naukę i zaprojektowanie porządnie kodu, nawet miesiąc, aby w końcu ruszyć się dalej. Powrót do programowania byłby błędem, bo oznaczałby regres, czyli to czego nauczyłem się zapomniałbym. Dlatego tworzenie kodu za pomocą przestrzeni nazw z funkcjami, zadeklarowanie w pewnym miejscu zmiennych, byłoby pewnym postępem i dobrym rozwiązaniem, a tym samym nie skomplikowane i pewnego rodzaju ułatwienie.

3.
Cytuj
Opakować w obiekt(register w konstruktorze, unregister w destruktorze) i użyć jako statyczna funkcji. Tak wszystkie glew itp. ja inicjalizuję. Wygodniejsze niż trzymanie osobnej sekcji w mainie...
Trochę źle napisałem, bo z tego wynikałoby, że klasy trzymam w kontenerze STL, co jest nie prawdą. U mnie mam jedną klasę, którą tylko raz deklaruję, a następnie za jej pomocą korzystam z jej metod, które z kolei operują na strukturze(opisującej okno) w części prywatnej.
class Window
{
      private:
           vector<Opis_okien> windows; // windows może być mylące tak samo jak nazwa klasy. Oknem tak na prawdę jest struktura. Klasa tylko pewnego rodzaju Manager'em

      public:
          Metody, konstruktory, destruktory itp.
};
A co miałeś na myśli pisząc?
Cytuj
register w konstruktorze, unregister w destruktorze

4.
Cytuj
Ciężko będzie się zgodzić... oceniłbym że troche źle Ci się wydaje :) Przecież wszystkie te frameworki mają funkcję create, która robiła by to samo co Twoja, z tym że.. u Ciebie ta create po prostu wywoływała by ich create.. Różnica może być taka, że to istniejące API pozwala Ci konfigurować parametry itd., więc trzeba napisać trochę kodu żeby powiedzieć JAK ma się dziać, a Twój silnik mógłby mieć to już napisane (hardcoded).. no chyba, że chciałbyś trochę elastyczności, to wtedy to "create" zaczyna przyjmować parametry i ciągnie się... i zamiast jednej funkcji masz kilka, i tak dalej... aż tworzysz swoje własne Qt2 :) przecież te biblioteki powstały właśnie "bo WinApi to jest trudne, zróbmy coś swojego prostszego". Potem Ty tworzysz framework "bo tam jest biliard funkcji, zrobię coś prostszego", a potem za 5lat ktoś spojrzy na Twój kod i uzna, że "lepiej napiszę nakładkę na ten kod, taką prostszą"...
No tak, to się nazywa postęp.
Swoją drogą, trochę źle odebrałeś moją motywację do napisania framework'a. Jeszcze raz zaznaczam, że nie piszę API, a Framework. Framework jest nakładką, dzięki, której nie muszę pisać tego samego kodu( w przypadku Qt, nie muszę tworzyć oddzielnej klasy, która dziedziczy po QtWindow lub QtWidget ( dawno nie używałem Qt, więc nie pamiętam jaka była to nazwa ) ).
Dodatkowo pamiętam, że z Qt były zawsze jakieś problemy, czy to z bibliotekami, linker'em( pomimo, że dołączałem lib'y ) oraz trzeba było samemu kompilować za pomocą Makefile, co czasami też sprawiało problemy.
Pomijam również, że Qt wymaga od nas zaawansowanej znajomości C++, o ile chcemy zrozumieć jak coś działa, dlaczego i nie robimy tylko metodą kopiuj-wklej z tutoriali ;)

Dodatkowo nie chcę pisać żadnej nakładki na dostępne API lub inne Framework'i, bo to nie jest moim założeniem. A jakby iść tym samym tropem, po co pisać własne nakładki, wrapper'y na biblioteki OGL/DX skoro jest Qt, GLFW itp. A jak każdy wie, powstaje dużo silników, czy to tu na stronie warsztatu, w studiach developerskich itp.
Np. nie podoba mi się GLFW, bo nie mogę wybrać, którego GPU chcę użyć do renderowania grafiki, wyłączyć VSync oraz wiele innych ograniczeń. Do tego korzystanie z kilku innych bibliotek. Nawet pisząc w Qt muszę dołączyć FMOD, PhysX/Bullet, Lua/Luabind itd. A moim założeniem jest napisać tylko Framework na róże środowiska ( Windows, Linux, w przyszłości może MacOS ) korzystając z natywnych API do tych systemów. Wtedy ja czy ktoś inny, nie musi się martwić jaka biblioteka została użyta, czy coś musi dołączyć, co się dzieje itp. Po prostu, wywołuje funkcję/metodę i coś działa. Może za pomocą parametrów sterować co ma się konkretnie dziać, np. za pomocą enum, bool itp.

5.
Cytuj
Bardzo dobry programista pisze wyśmienity kod. Genialny programista używa kodu bardzo dobrych programistów
To zależy, bo kod może być prosty, ale nie wydajny. Wydajny, ale skomplikowany - tysiące funkcji, korzystanie z dziedziczenia itp.
Bądź czasami kod jest stary i do tego czasu powstało już dużo lepszych algorytmów lub można poświęcić więcej czasu i okaże się że można to samo zrobić szybciej. Dzięki temu powstaje dużo algorytmów w czasie stałym lub liniowym. Gdyby nie to, nadal byśmy uważali że sortowanie bąbelkowe jest najłatwiejsze i najszybsze ;) Pewne terminy spowalniają nas, czy to wyraz utopia, czy to powiedzenia - nie wynajduj znowu koła na nowo itp. Jednakże praktyka pokazuje coś innego, cały czas technologia jest ulepszana, gdyby nie to, nadal pisalibyśmy w Assembly lub bitowo.

6.
Cytuj
Dla mnie to jest to samo co zmienna globalna, wszystko ma do niej dostęp i nikt nie kontroluje co się z tym kontrolerem dzieje
Cytuj
To jest anty-programowanie obiektowe :)
To w końcu jaka architektura kodu jest najlepsza? Przestrzeń nazw nie bo to jest zbliżone do globalnych zmiennych/funkcji. Zmienne w klasach nie bo to antywzorzec, ok. To trzymanie w Manager'ze zmiennych i za pomocą funkcji operowanie na zmiennych, nie bo to również antywzorzec. Coś mi się wydaje, że wyraz antywzorzec jest tak naciągany jak wyraz utopia itp. To jest jakaś moda?

7.
Cytuj
Powiem w skrócie, problem zmiennych globalnych jest taki, że DOWOLNE miejsce kodu jest potencjalnym miejscem błędu i wysypania się aplikacji, bo "5 miesięcy temu, w funkcji XYZ, założyłem że ta zmienna będzie taka, a okazało się teraz że coś w funkcji ABC zmieniłem i już jest siaka, błędu szukałem 3 dni i nocy" :)
Szukanie błędu 5 dni to pikuś, ja przy użyciu obiektowego programowania, hermetyzacji danych itp. szukałem tydzień lub miesiąc danego błędu, więc to nie jest powód do omijania funkcji/zmiennych globalnych. Do tego przestrzeń nazw jest po to, żeby funkcje/nazwy nie kolidowały ze sobą. Tak samo debugger powinien poinformować nas, że jest niezgodność typów, np. chcę utworzyć okno, a przekazuję referencję do tekstury. Każdy debugger zwraca taki komunikat o błędzie. Do tego, samo użycie domyślnych/wbudowanych funkcji C/C++ jest zbudowane na przestrzeni nazw i jakoś błędów nie ma ;)
Zresztą jak zrobię błąd, jak będę funkcję wywoływał w ten sposób:
int main()
{
     Window::Create( ... );
     Window::Resize( ... );

     // Poniższy przykład pokazuje, że nie ma prawa wystąpić błąd( inna przestrzeń nazw )
     Texture::Load( ... );
     Shader::Load( ... );

     return 0;
}
Dodatkowo nie ma czegoś takiego jak private, public, protected w namespace? Bo już nie mam pomysłu na architekturę kodu :/ Masakra jakaś...

Edit:
Może wezmę się znowu za pisanie kółko-krzyżyk, tak aby nauczyć się programować obiektowo. Co o tym myślicie? Ale czy to nie będzie regres? Zresztą i tak, to nie rozwiąże tego problemu, bo zaprojektować kod i tak kiedyś trzeba będzie. W konsoli tę grę to będzie w miarę prosto i szybko napisać, ale okna i grafika( OGL ) to już wyższy poziom i inne podejście do problemu, kodu.
« Ostatnia zmiana: Marzec 30, 2014, 19:56:54 wysłana przez Xenox93 »

Offline lethern

  • Użytkownik

# Marzec 30, 2014, 20:10:39
Wydaje mi się, że psychologicznie przyjąłeś pozycję obronną, i odpowiadasz byle by coś obronić... (ale z drugiej strony, ta dyskusja jest lekko przesadzona). Wrażenie moje stąd, że teraz z mało czym się z Tobą zgodzę
Cytuj
. Framework jest nakładką, dzięki, której nie muszę pisać tego samego kodu( w przypadku Qt, nie muszę tworzyć oddzielnej klasy, która dziedziczy po QtWindow lub QtWidget ( dawno nie używałem Qt, więc nie pamiętam jaka była to nazwa ) ).
Właśnie QT jest pięknym frameworkiem, który powoduje że wiele rzeczy nie musisz pisać. Choćby ich QtString i QObject, daleko nie szukając. Inna sprawa, gier się raczej w nim nie pisze
Jeżeli "muszę dziedziczyć po QtWindow" to dla Ciebie problem i przeszkoda, żeby używać Qt, to jestem bardzo zasmucony, nie za dobre podejście ;p
Cytuj
To zależy, bo kod może być prosty, ale nie wydajny
To nie o to chodzi. Chodzi o to, że będziesz ten program pisał 5 lat i nadal go nie skończysz. Dlatego piękne jest w tym stwierdzeniu "genialny programista używa czyjegoś kodu"
Cytuj
Zmienne w klasach nie bo to antywzorzec
pierwszy raz słyszę taką bzdurę. Jeśli takie rzeczy wyciągasz z internetu, to odepnij kabel, bo robią kurcze krzywdę
Cytuj
To trzymanie w Manager'ze zmiennych i za pomocą funkcji operowanie na zmiennych, nie bo to również antywzorzec
jw.
Cytuj
Szukanie błędu 5 dni to pikuś, ja przy użyciu obiektowego programowania
Nie... jeśli zmienna jest używana przez metody, to szukasz błędy w 1 metodzie, w 5 metodach, albo w więcej... Jeśli zmienna jest globalna, to szukasz błędy w całym projekcie, w 10000 funkcjach. Nie ma różnicy?
Cytuj
Do tego przestrzeń nazw jest po to, żeby funkcje/nazwy nie kolidowały ze sobą.
To prawda.. ale to oznacza, że nie powinieneś używać słówka namespace w swoim projekcie póki ten problem Cię nie dotyczy. Prawda? Nie kupujesz chyba spray'u na komary kiedy jedziesz na antarktydę?
« Ostatnia zmiana: Marzec 30, 2014, 20:17:16 wysłana przez lethern »

Offline ArekBal

  • Użytkownik

  • +1
# Marzec 30, 2014, 20:25:15
Cytuj
To w końcu jaka architektura kodu jest najlepsza? Przestrzeń nazw nie bo to jest zbliżone do globalnych zmiennych/funkcji. Zmienne w klasach nie bo to antywzorzec, ok. To trzymanie w Manager'ze zmiennych i za pomocą funkcji operowanie na zmiennych, nie bo to również antywzorzec. Coś mi się wydaje, że wyraz antywzorzec jest tak naciągany jak wyraz utopia itp. To jest jakaś moda?
Koduj, staraj się kodować dobrze i szukaj najlepszego lekarstwa na daną bolączkę, a nie panaceum w postaci Managerów które defacto są zkonretyzowanymi kontenerami. Kontenerów i wrapperów nikt ci nie broni używać... Byle byś w zgodzie z YAGNI używał ich sporadycznie... i nazywał je odpowiednio... i nie robił ich globalnymi.

Offline Xenox93

  • Użytkownik

# Marzec 30, 2014, 21:18:45
1.
Cytuj
Wydaje mi się, że psychologicznie przyjąłeś pozycję obronną, i odpowiadasz byle by coś obronić... (ale z drugiej strony, ta dyskusja jest lekko przesadzona). Wrażenie moje stąd, że teraz z mało czym się z Tobą zgodzę
Bo przyzwyczaiłeś się już do tego co obecnie mamy na rynku. Nie wyobrażasz sobie pisać już w czymś co byle Kowalski znający podstawy C++ może napisać to samo co Ty musiałbyś pisać tydzień.
Hmm... czy przyjąłem pozycję obronną? Na pewno, ale to od samego początku, bo nie dam sobie wmówić, że tworzenie 20 klas, po to, aby utworzyć 2 okna i kontrolki oraz callback'i do nich. Nie wspomnę już o obsłudze sieci, dźwięku, AI, skryptu, wejścia( klawiatura, pad itp. ), kontekstu OGL'a itd. itd. co powoduje, że mam 1 tys. klas, część z nich można byłoby zminimalizować do jednej lub dwóch.

Nie bronię się po to, aby to wyglądało na to, że nie chcę przyjąć czegoś do wiadomości. Po prostu, pewne rzeczy wydają mi się pozbawione sensu, tak samo jak moje pomysły.

Nawet we wcześniejszych komentarzach pisałem już, że wasze propozycje i rady dały mi dużo do myślenia. Nawet byłem skory z dużo rzeczy zrezygnować, bo fakt, były trochę przegięciem.

2.
Cytuj
Właśnie QT jest pięknym frameworkiem, który powoduje że wiele rzeczy nie musisz pisać. Choćby ich QtString i QObject, daleko nie szukając. Inna sprawa, gier się raczej w nim nie pisze
Jeżeli "muszę dziedziczyć po QtWindow" to dla Ciebie problem i przeszkoda, żeby używać Qt, to jestem bardzo zasmucony, nie za dobre podejście ;p
Zacząć trzeba od tego, że dziedziczenia powinno się unikać, a stosować je jak już nie ma innego wyjścia. Pod względem wydajności i skomplikowania. Zresztą tę opinię na temat dziedziczenia, zdobyłem po czytaniu innych komentarzy i rad na forum tej strony.
Dziedzicząc po QtWindow muszę użyć metod o tej samej nazwie co Qt. Czy to pętla, callback'i czy utworzenie nawet kontekstu OGL'a powoduje, że wszystko od podstaw muszę napisać, tak jakbym pisał w WinAPI. Rozumiem, że biblioteka musi oferować bezpośredni dostęp do innych API, ale również powinna oferować wywołanie jednej funkcji, np. tworzącej kontekst, podanie rozdzielczości, czy chcę RGB lub RGBA. Pisząc w Qt miałem wrażenie jakbym pisał w GLFW. Musiałem utworzyć metodę - init(?), we własnej klasie, która dziedziczyła znowu, po QtOpenGL(?). Mnie interesuje biblioteka, którą tylko dołączam, deklaruję jej obiekt, wywołuję metodę CreateWindow, InitializeOpenGL, itp., a gdy, np. chcę coś edytować, zmienić lub np. chcę użyć DX, a biblioteka/framework nie korzysta z tego API, dopiero wtedy dziedziczę po klasie Graphic/Render, to wtedy widze w tym sens, nawet w tworzeniu nowej klasy.

3.
Cytuj
To nie o to chodzi. Chodzi o to, że będziesz ten program pisał 5 lat i nadal go nie skończysz. Dlatego piękne jest w tym stwierdzeniu "genialny programista używa czyjegoś kodu"
Owszem, masz rację i głupotą byłoby się nie zgodzić. Jednakże, ma to sens, gdy ktoś oferuje bibliotekę/API/Framework wraz ze sprzyjającą licencją. Tu chyba się zgodzisz ;) Teraz właśnie mi się przypomniało, że Qt nie pozwala na komercyjne wydanie programu, dopiero za wykupieniem licencji. Niby drobna rzecz, ale jak łatwo można przyzwyczaić się do czyjegoś rozwiązania/wygody.

4.
Cytuj
pierwszy raz słyszę taką bzdurę. Jeśli takie rzeczy wyciągasz z internetu, to odepnij kabel, bo robią kurcze krzywdę
Ale to tu na forum takie rzeczy wyczytałem. Już pewną koncepcję miałem, nawet dziedziczenie, tworzenie metod statycznych itd. itd., ale zawsze ktoś napisze, że to jest złe, bo antywzorzec lub czegoś się nie praktykuje bądź coś działa, ale tak się nie powinno pisać. Pisząc: Zmienne w klasach nie bo to antywzorzec, mam na myśli taką konstrukcję:
class Window lub WindowManager
{
        private:
            vector<struktura_okna> windows; <- to tu jest prawdziwe okno, tu są uchwyty HWND itp.

        public:
           // Konstruktory, Destruktor, Metody operujące na oknach, np. Create( ... );
};
Ten kod przewinął się już nie raz. Więc podchodzi mi to już pod spam, a nie zamierzam robić czegoś podobnego.

5.
Cytuj
Nie... jeśli zmienna jest używana przez metody, to szukasz błędy w 1 metodzie, w 5 metodach, albo w więcej... Jeśli zmienna jest globalna, to szukasz błędy w całym projekcie, w 10000 funkcjach. Nie ma różnicy?
Teoretycznie masz rację i tak też myślałem, ale czasami okazywało się że była literówka w kilku miejscach, nawet w pętli programu albo przekazywałem zmienną, która powinna mieć coś dopisane, a debugger nie wyświetlił informacji o niepoprawnej operacji :/ Ale owszem, masz racje, że zawęża do obszar poszukiwań.

6.
Cytuj
To prawda.. ale to oznacza, że nie powinieneś używać słówka namespace w swoim projekcie póki ten problem Cię nie dotyczy. Prawda? Nie kupujesz chyba spray'u na komary kiedy jedziesz na antarktydę?
Na razie nie, ale jak zacznę korzystać z grafiki( OGL ), to będę miał podobne konstrukcje kodu dla Tekstury, Shader'a, Materiału, Modeli 3D itp. Wtedy może pojawić się problem. Dodatkowo rację mają inni pisząc: jaki sens ma tworzenie klasy Window, skoro ona nie jest oknem, a trzyma wszystkie okna w jednym miejscu i za pomocą metod zarządza/robi coś z nimi. Wtedy sens ma jedynie przestrzeń nazw, bo nic innego nie przychodzi mi na myśl. Dziedziczenie odpada, bo spowalnia to kod, a do gier to na pewno się nie przyda. Więc już brak pomysłów, Ameryki raczej nie odkryję :/

7.
Cytuj
Byle byś w zgodzie z YAGNI używał ich sporadycznie... i nazywał je odpowiednio... i nie robił ich globalnymi.
Owszem, zgadzam się z Tobą w 100%, ale jak mam nazwać klasę, która przechowuje w sobie kontener STL z oknami oraz klasa ma w sobie metody, które robią coś na tych oknach, czy to ich tworzenie, czy to zmiana rozmiaru( za pomocą metod dostępnych przez dane API ) ? WindowManger - może być mylący. Window powodował u innych oburzenie i coś nie logicznego. Już nawet zrozumiałem, że lepiej nie bawić się w Manager'y i odpuściłem sobie, ale już niczego nie wymyślę. U góry w tym komentarzu napisałem już kod(?), pseudokod(?), jak mogłaby wyglądać klasa. Na pewno struktura, która trzyma uchwyty okien itp. jest mi potrzebna. Z tego nie mogę zrezygnować, bo chciałbym dać możliwość tworzenie dowolnej ilości okien, a wszystkie dodawać dynamicznie, czy to w C++ czy to w skrypcie.

PS. Może to wygląda na to, że się bronię, ale tak nie jest. Nie zamierzam pisać kodu, który będzie robił to samo co inne biblioteki. Nie chcę pisać drugiego Qt, GLFW :/ Po prostu, mam dość pisania ręcznie za każdym razem tych samych funkcji, np. wolę utworzyć jedną metodę/funkcję Resize i nie obchodzi mnie co się w środku dzieje, na ogół aby zmienić rozmiar okna nie wystarczy wywołać jedną metodę. Zmiana rozmiaru to pikuś, jazda zaczyna się przy tworzeniu okna lub renderowaniu modeli 3D/2D, w środku dzieje się na prawdę sporo. Wystarczy, że przekaże objekt, model do wyrenderowania, a funkcja sama sobie dobierze najlepszą opcję( np. program wykrył, że można renderować za pomocą VBO ). Gdybym pisał sztucznie, deklarowałbym gdzieś kontener STL, za pomocą globalnych funkcji wykonywałbym operacje na danych wejściowych/strukturze, np. oknie. Następnie miałbym dodać taki bajer to nagle okazałoby się że pogubiłbym się, szansa na błąd wzrastałaby z nową to ilością kodu/funkcjonalnościami. Podobny już pomysł wprowadziłem w życie, podczas tworzenia okna i kontekstu OGL'a, sprawdzałem czy jest wsparcie dla Shader'ów oraz jaki jest wspierany sposób renderowania i kod działał bez problemu, a jaka wygoda.

Edit:
Ale jak już nie będzie innego wyjścia, to będę musiał się pozbyć kontenera STL z klasy Window. A tak w ogóle to może nawet w funkcji main będę deklarował tablicę lub tu użyję vector'a lub coś podobnego. Ale wolałbym to zostawić jako alternatywę.
int main()
{
     vector<Window> windows;

     windows.push_back( Window( ... ) );
     [...]

     windows[0].Resize( 800, 600 );

     return 0;
}
« Ostatnia zmiana: Marzec 30, 2014, 22:12:57 wysłana przez Xenox93 »

Offline lethern

  • Użytkownik

# Marzec 30, 2014, 22:36:39
Wiesz, ja kiedyś czytałem sporadycznie blogi koderskich (anglojęzyczne) i na jednym z nich były ciekawe rozważania odnośnie... tworzenia klasy coś-tam-thing. Na przykład, proponuję Ci nazwać swoją klasę WindowsThing, i wrzucić tam ten wektor. W przyszłości albo nazwiesz ją sensownie, albo zmienisz na Application, albo wywalisz wektor bo okaże się zbędny, albo cokolwiek..
Co do dziedziczenia i wydajności - absolutnie się nie zgodzę. Ja nie zwlekałbym nawet sekundy żeby zrobić u siebie obiektu, który dziedziczy po 10 klasach i połowę metod ma wirtualną. Optymalizacja omijaj szerokim łukiem, ale o tym już w internetach przeczytasz. (Dlaczego? Bo to bardzo trudna działka, i są nawet artykuły w internecie, gdzie po optymalizacji (np. return-by-value temat) aplikacja działa wolniej, ponieważ kompilator mógł zrobić mniej optymalizacji niż przed zmianami programisty. Mówi się, że optymalizować należy algorytm ORAZ wąskie gardła, to jest fajnie określone. Ale dziedziczenie nie zalicza się do żadnego z tych dwóch..)
Powiedziałbym, że takie rozważania typu "znam 100 dobrych zwyczajów, z czego wszystkie sobie przeczą, co mam zrobić?" - są bez sensu, ale z drugiej strony właśnie jest w tym też troche odkrywania prawdy i trochę nauki. Nie wiem czy podkreśliłem już, ale ważne są powody jakiegoś problemu, jak Ci wspomniałem przykład zmiennych globalnych, i rozwiązanie problemu (czyli zamknięcie zmiennych w obiekt, wraz z metodami), i to samo można zastosować do.. nie wiem, managerów... Manager zły? To nazwij tę klasę "WindowThing" ; ) (nie znajdę teraz tego artykułu, więc nie będę tego rozwijał... Cóż, zbyt sporadycznie na tym forum jestem żeby je oceniać, jeśli trafiasz na choćby jedną osobę przez którą się cofasz, to będziesz miał więcej pytań niż odpowiedzi, itd... może będziesz chciał część czasu poświęcić też na czytanie, no nie wiem, np.  http://blog.codinghorror.com)
« Ostatnia zmiana: Marzec 30, 2014, 22:48:36 wysłana przez lethern »

Offline Xirdus

  • Redaktor

# Marzec 30, 2014, 23:27:26
Co do dziedziczenia, to nie chodzi tu o wydajność - chodzi o to, czy naprawdę jest to potrzebne. Gdy masz dziedziczenie, funkcjonalność obiektu rozrzucona jest po N klasach - a oczywistym jest że ogarnięcie N klas jest trudniejsze od 1 klasy. Dziedziczenie jest dobre wtedy i tylko wtedy, gdy masz więcej niż jedną klasę dziedziczącą po klasie bazowej i obiekty obu klas używane są jednocześnie w tym samym miejscu w kodzie w ten sam sposób. Pamiętać też trzeba koniecznie o zasadzie podstawienia Liskov.