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

Offline Xender

  • Użytkownik

# Marzec 31, 2014, 14:08:45
1.Fatk, faktem, że wydajność jest gorsza od C++, ale lepsza niż takiego Lua.
Pythona? Pypy czy innego może, ale CPythona (referencyjny interpreter)? Lua ma opinię języka lekkiego i szybkiego, więc szczerze wątpię.

Offline Mr. Spam

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

Offline Xenox93

  • Użytkownik

# Kwiecień 02, 2014, 14:27:59
Ok, tak więc, dzięki za pomoc, serio. Dużo mi pomogliście, część rzeczy zrozumiałem, a artykuły przeczytam ;)
Aby nie stać w miejscu, będę musiał w końcu coś napisać, bo mam wrażenie, że tracę czas :/
Rozważam na chwilę obecną dwa podejścia do napisania tej części kodu:

1.
namespace Window
{
        vector<Uchyt Okna> windows;

        bool Create( ... ) {  }
        void Remove( int id ) {  }
}

int main()
{
    Window::Create();

    return 0;
}
Tylko nie pasuje mi to, że nie mogę zadeklarować zmiennej "windows" jako prywatną.

2.
class WindowsThing
{
    private:
        vector<Uchyt Okna> windows;

    public:
        WindowsThing() {  }
        ~WindowsThing() {  }

        bool Create( ... ) {  }
        void Remove( int id ) {  }

        vector<Uchyt Okna> GetWindows() { return windows; }
};

int main()
{
    WindowsThing windowsThing;
    windowsThing.Create();

    return 0;
};

Drugi sposób zawsze stosowałem, więc zatoczyłbym koło. A pierwszy wygląda jak ten z C.
Hmm, a może pójść na przód i wdrożyć się w programowanie obiektowe ? ;) Bo wydaje mi się że nadszedł już czas, tym bardziej, że na studiach będę uczył się obiektowo pisać, do tego będę miał na zaliczenie napisać projekt. Więc upiekł bym dwie pieczenie na jednym ogniu. Obiektowo już nie raz pisałem, nie był to jakiś skomplikowany kod. Nawet co nieco rozumiem, czytałem kiedyś nawet książkę, artykuły itp. Jednakże zawsze pojawiał się problem, jak tu logicznie zaplanować kod.

Bo bez sensu byłoby znowu pisanie tego samego kodu z drugiego punktu, bo znowu okaże się, że próba dodania czegoś oznacza klęskę, bądź kod wygląda strasznie i chaotycznie, że aż człowiek stwierdza, że nie ma sensu naprawiać czegoś, a napisać wszystko i zaprojektować kod od nowa :/

Dodatkowo struktura kodu powinna być łatwa, tak aby dało się przenieść pewne funkcje, klasy do skryptu.

Tak więc, dzięki. Teraz raczej wezmę się za pisanie, no chyba, że ktoś ma jeszcze pomysł lub jakiś artykuł, który wytłumaczyłby mi coś, chętnie poczytam ;)

Offline ArekBal

  • Użytkownik

# Kwiecień 02, 2014, 16:00:25
Oeza czemu nie możesz tego zrobić jak wszyscy?

Mniej więcej tak...
class Window
{
  HWND handle_;
  uint width_;

  void width(uint width)
  {
width_ = width;
    if(isInitialized)
    {
#ifdef WIN32
       SetWindowPos(...);
#endif
    }
  }
};
typedef std::shared_ptr<Window> WindowPtr;

int main()
{
auto window = std::make_shared<Window>();
window->width(1100);
window->init(...);

Dispatcher::Curr().Start();
}

//albo
class App
{
  std::vector<Window> windows;
  //albo
  std::vector<WindowPtr> windows;

  void start()
  {
    for(auto win: windows)
    {
      win.init();
      //albo
      win->init();
    }

    // msg loop
  } 
};

class MyApp : App
{
  virtual void init()
  {   
    windows.emplace_back();
    auto& win = windows.back();
    win.width(1050);

    App::init();
  }
};

int main()
{
MyApp app;
app.start();
}
« Ostatnia zmiana: Kwiecień 03, 2014, 03:05:42 wysłana przez ArekBal »

Offline Xenox93

  • Użytkownik

# Kwiecień 02, 2014, 22:43:51
@ArekBal: Wcześniej w ten sposób pisałem kod. Ale jak widać, ma słabą konstrukcję, bo ciężko jest dodać coś nowego. Na dodatek, próba przeniesienia tego do skryptu jest utrapieniem. Ale ok, jak widać, jest to jedyne rozwiązanie.

Ciekawi mnie jedno, czy warto utworzyć strukturę, która będzie potrzebna do opisania okna do utworzenia, czyli:
windows.Create( Struktura{ "Tytuł", 800, 600, windowed, STYLE itp. } );
czy lepiej od razu utworzyć metodę, ale trochę będzie argumentów :/

windows.Create( "Tytuł", 800, 600, windowed, STYLE itp. );
Może tego nie widać przy wywołaniu funkcji/metody, ale przy deklaracji jest to uciążliwe...
class WindowThing
{
         private:
             vector<HWND> hwnd;

         public:
             WindowThing() { ... }
             WindowThing( const WindowThing &wT ) { ... }
             WindowThing( Struktura str ) { ... }
             // czy
             WindowThing( string Title, unsigned short width, unsigned short height, bool isFullScreen, itd. ) { ... }

             ~WindowThing() { ... }

             [...]

             bool Create( Struktura str. );
             // czy
             bool Create( string Title, unsigned short width, unsigned short height, bool isFullScreen, itd. );
};
Jak widać, struktura jest wygodna.

Tak wiec, wygląd samej klasy jest ok. Dodatkowo mógłbym w przyszłości utworzyć wirtualne metody, które zastępowałbym, dziedzicząc po klasie Window / WindowThing. Tak więc, pozostanę przy starej architekturze kodu, która jest taka sama jak ArekBal. Tylko chyba pominę stosowanie smartpointer'ów, bo ciężko za ich pomocą dziedziczyć lub przekazywać inne funkcje/metody jako argumenty metod. Wtedy przydaje się zwykły wskaźnik.

Offline ArekBal

  • Użytkownik

# Kwiecień 03, 2014, 03:04:43
Te dane tworzenia wypełnij defaultami i wystaw jako właściwości. Potem przy tym twoim create czy init je poustawiasz. Bo akurat te wymienione przez ciebie pola można potem jak już okno istnieje zmieniać więc brak tu potrzeby na oddzielną strukturę... może tylko szkoda że po utworzeniu okna informacje o nim przechowujesz ty oraz OS. Ale to taka decyzja projektowa jaką się podejmuje na co dzień. Nie ma co płakać przy wyborze jednej opcji nad drugą... jeżeli wiesz z jakiego powodu wybrałeś a) zamiast b) to jest OK.

Bez smart pointerów nie ma jak przekazywać zależności na obiekty w rozsądny sposób. Np. możesz mieć taki niezależny od okna widget w aplikacji co jest spięty z danym oknem. Bez smart pointerów musisz albo ten widget uczynić składnikiem tego okna, albo okno składnikiem widgetu, albo i widget i okno składnikami jeszcze czegoś... Ale to znowu taka decyzja projektowa... Czasami lepiej tak, a czasami lepiej siak, zależy od zastosowania tych klas. Akurat Window dla mnie mają dość szerokie.
 
Jeśli się martwisz o dziedziczenie i rzutowanie w przypadku smart pointerów to nie potrzebnie. Wszystko co naprawdę potrzebne w tej dziedzinie już jest.

Owszem... pisanie co chwila make_shared i pilnowanie właściwych argumentów jest pewną bolączką(taką samą jak przy emplace_back) ale to właściwa droga przez mękę. Jeśli kogoś to moooocno boli to może się pokusić o opakowanie tego w jakąś statyczną Create... czy add... ale to plaster spod którego będzie ciekło.

Ze smart pointerów można wyciągać zwykły wskaźnik poprzez get().
Tak gwoli ścisłości... smart-pointery nie wykluczają pointerów w części przypadków np. jako parametrów do niektórych funkcji.

Offline lethern

  • Użytkownik

# Kwiecień 03, 2014, 04:38:33
Obecnie kod który podałeś... jest dziwny, używasz konstruktora jeśli konstruujesz tę właśnie klasę, natomiast używasz "create" jeśli klasa jest jakimś tworzycielem/zarządcą/managerem/fabryką/etc. Ponad to, dlaczego Create nic nie wraca? (może powinno nazywać się Init. Znaczenie nazwy jest wbrew pozorom ważne dla czytelności. Jeśli widzisz WindowFactory::Create, Window::Create, WindowManager::Create, to zaczynasz wątpić czy pod tym słowem na pewno kryje się to samo..).

Serio, hm.. średnio to wygląda. Wróciłbym do pomyslu: Najpierw napisz kod, potem go opakuj.
Żeby się za wcześnie nie okazało, że przeczytasz u siebie to:
void najwyzsza_funkcja(){
   title= ...
   width= ...
   height = ...
   WindowThing window = WindowFactory.Create( title, width, height, fullScreen );
}

WindowFactory::Create( string Title, unsigned short width, unsigned short height, bool isFullScreen ){
   return new WindowThing( title, width, height, fullScreen );
}

WindowThing::WindowThing( string Title, unsigned short width, unsigned short height, bool isFullScreen ){
   init( title, width, height, fullScreen );
}

WindowThing::init( string Title, unsigned short width, unsigned short height, bool isFullScreen ){
   ...
}
Myślę, że wolałbyś to wszystko zrobić z jak najmniejszą ilością funkcji, parametrów, jak i liczbą linijek. Bo jeśli cała ta magia ma Ci "pomóc" w edytowaniu kodu, to okazuje się, że zmiana parametru przysparza modyfikację 3 plików, 4 funkcji, 4 list argumentów, 4 przypisań, 4 wywołań.... A przecież to miało UŁATWIAĆ??
Jeśli osiągniesz taki "minimalny przyzwoity kod", to moim zdaniem NIEWAŻNE czy nazywa się to obiektowe, czy funkcyjne, strukturalne, czy aspektowe programowanie, jeśli będzie to krótki i ładny kod, ode mnie masz 10/10. W tym miejscu, jeśli najdzie Cię ochota żeby coś zmodyfikować, rozszerzyć i tak dalej, to masz pole do popisu - napisać kod który spełnia konkretne zadanie. Bo teraz ciężko zdefiniować rozwiązanie, gdy sprawa jest dość rozmyta, a problem w zasadzie nieokreślony
Tak mi się przypomniało... jeśli nie wiadomo co wybrać, to zawsze pozostaje "najlepszy kod to krótki kod".
lektura. A tutaj to co mi się przypomniało nr.2: http://www.devblogi.pl/
« Ostatnia zmiana: Kwiecień 03, 2014, 04:53:51 wysłana przez lethern »

Offline Xenox93

  • Użytkownik

# Kwiecień 04, 2014, 21:27:35
Cytuj
Żeby się za wcześnie nie okazało, że przeczytasz u siebie to:
void najwyzsza_funkcja(){
   title= ...
   width= ...
   height = ...
   WindowThing window = WindowFactory.Create( title, width, height, fullScreen );
}

WindowFactory::Create( string Title, unsigned short width, unsigned short height, bool isFullScreen ){
   return new WindowThing( title, width, height, fullScreen );
}

WindowThing::WindowThing( string Title, unsigned short width, unsigned short height, bool isFullScreen ){
   init( title, width, height, fullScreen );
}

WindowThing::init( string Title, unsigned short width, unsigned short height, bool isFullScreen ){
   ...
}
Myślę, że wolałbyś to wszystko zrobić z jak najmniejszą ilością funkcji, parametrów, jak i liczbą linijek. [...]
Dokładnie, nie chciałbym pisać niepotrzebnie tyle argumentów funkcji, lepiej użyć struktury. Dodatkowo tak jak już zwróciłeś uwagę, że za pomocą jednej lub kilku funkcji i argumentów/struktur, które opisywałyby jak ma zostać utworzony dany obiekt, chciałbym utworzyć okno itp.

Zresztą czas najwyższy nie przejmować się głupotami i napisać jakiś kod, który będzie działał.