Tag: C++

Mobile Periodic Table of elements.

Mobile Periodic Table of elements.

The application title reveals everything – this is a full and interactive periodic table of elements, which is well shown in the following graphic. Our app allows you to view the full table in which you can choose a single chemical element and view its detailed […]

Anagramer. Find words in dictionary file C++/Qt.

Anagramer. Find words in dictionary file C++/Qt.

Below sample of code to find word containing the same letters + one that is not the same but create new word: tor -> sort -> sport The code can get dictionary and word that should be found: #include <iostream> #include <QApplication> #include <QStringList> #include […]

Wzorzec obserwator C++/Qt

Wzorzec obserwator C++/Qt

Często się zdarza że programiści napotykają problem we współczesnych programu posiadające interfejs użytkownika (GUI), muszą reagować na zmiany danych w kilku różnych miejscach jednocześnie. Do sytuacji takiej może dojść wtedy gdy pracujemy na tych samych danych, które możemy edytować w kilku miejscach jednocześnie np. wykresy obrazujące takie same dane. Zmiana wartości na jednym wykresie implikuje zmianę wartości na pozostałych wykresach.

W przypadku kiedy mamy do czynienia z kilkoma obiektami możemy wykorzystać mechanizm sygnałów i slotów w Qt, jednak jeżeli jednak liczba obserwowanych obiektów, które się zmieniają nie jest zdefiniowana lub dotyczy znacznej grupy obiektów możemy zbudować osobną klasę zwaną Obserwatorem mającą na celu powiadamianie obiektów o występujących zmianach.

Pomimo że istnieje wiele różnych implementacji tego samego wzorca mają one elementy wspólne takie jak:

Wszystkie z obiektów można podzielić na dwie osobne grupy wydawców i klas pełniących rolę obserwatorów
Każda z implementacji zakłada że jest jeden obiekt, które informuje inne obiekty o zmianach
Mechanizm wysyłania informacji do pozostałych klas jest zdefiniowany w całości w klasie bazowej wydawcy.

Zalety i wady

Zalety:

Luźna zależność między obiektem obserwującym i obserwowanym. Ponieważ nie wiedzą one wiele o sobie nawzajem, mogą być niezależnie rozszerzane i rozbudowywane bez wpływu na drugą stronę.
Relacja między obiektem obserwowanym a obserwatorem tworzona jest podczas wykonywania programu i może być dynamicznie zmieniana.
Możliwość zablokowania klientowi drogi do bezpośredniego korzystania ze złożonego systemu, jeśli jest to konieczne.

Wady:

Obserwatorzy nie znają innych obserwatorów, co w pewnych sytuacjach może wywołać trudne do znalezienia skutki uboczne.
Zastosowanie

Wzorzec Obserwatora sprawdza się wszędzie tam, gdzie stan jednego obiektu uzależniony jest od stanu drugiego obiektu.

Implementacja

//Obserwator:
class Obserwator {
public:
    virtual void update() = 0;
};
//Obserwowany:

class Obserwowany {
protected:
    std::list <Obserwator*> obserwatorzy;
public:
    void dodaj(Obserwator *o) {
        obserwatorzy.push_back (o);
    }
    void usun(Obserwator *o) {
        obserwatorzy.remove (o);
    }
 
    void powiadom () {
        std::list<Obserwator *>::iterator it;
        for (it = obserwatorzy.begin(); it != obserwatorzy.end(); it++) {
            (*it)->update ();
        }
    }
};

Obserwowany Konkretny:

Dziedziczenie wielokrotne dostępne w C++ jest często używane w wzorcu Obserwatora

class Miod {
protected:
    int ilosc;
public:
    Miod (int q) {
        ilosc = q;
    }
 
    int pobierzIlosc () {
        return ilosc;
    }
 
    void ustawIlosc (int q) {
        ilosc = q;
    }
};
 
class ObserwowanyMiod : public Obserwowany, public Miod {
    std::string stan;
public:
    ObserwowanyMiod (int q) : Miod(q) {
    }
 
    std::string pobierzStan () {
        return stan;
    }
 
    void ustawStan (const std::string& s) {
        stan = s;
        std::cout << "Stan: " << stan << std::endl;
        powiadom();
    }
};

Obserwator Konkretny:

class ObserwatorMis : public Obserwator {
protected:
    int misId;
    ObserwowanyMiod *miod;
public:
    ObserwatorMis (ObserwowanyMiod *h, int id) {
        miod = h;
        misId = id;
    }
    void update () {
        std::string stan = miod->pobierzStan();
        if (!stan.compare ("Sa ludzie blisko miodu")) {
            std::cout << "Mis" << misId << ": Czekam w ukryciu" << std::endl;
        } else if (!stan.compare ("Nie ma ludzi blisko miodu")) {
            std::cout << "Mis" << misId << ": Kradne miod" << std::endl;
            miod->ustawIlosc(miod->pobierzIlosc()-1);
        } else if (!stan.compare ("Ida ludzie")) {
            std::cout << "Mis" << misId << ": Uciekam" << std::endl;
        }
    }
};

Przykład użycia:

int main() {
    ObserwowanyMiod miod (5);
    Obserwator *mis1 = new ObserwatorMis(&miod, 1);
    Obserwator *mis2 = new ObserwatorMis(&miod, 2);
 
    miod.dodaj(mis1);
    miod.dodaj(mis2);
 
    std::cout << "Ilosc miodu: " << miod.pobierzIlosc() << std::endl;
 
    miod.ustawStan("Sa ludzie blisko miodu");
    miod.ustawStan("Nie ma ludzi blisko miodu");
    miod.ustawStan("Ida ludzie");
 
    std::cout << "Ilosc miodu: " << miod.pobierzIlosc() << std::endl;
    delete mis1;
    delete mis2;
    return 0;
}
Pytania rekruterów na stanowisko C++/Qt Developer.

Pytania rekruterów na stanowisko C++/Qt Developer.

1. Co to jest dziedziczenie? 2. Czym jest polimorfizm? 3. Jakie znasz wzorce strukturalne? 5. Do czego służy rzutowanie? 6. Czy język C++ jest językiem obiektowym? 7. Co to jest kompilacja? 8. Czym jest linkowanie? 9. Co to jest zmienna statyczna? 10. Czym jest zakres […]

How to initialize static QMap?

How to initialize static QMap?

Jak zainnicjalizować mapę w qt.

Wzorzec Adapter C++/Qt

Wzorzec Adapter C++/Qt

Zastosowanie

Adapter inaczej nazywany Nakładką (ang. wrapper) to strukturalny wzorzec projektowy, którego zadaniem jest stworzenie spójnego interfejsu dla dwóch niekompatybilnych klas. Adapter przekształca interfejs jednej z klas na interfejs drugiej.

Adapter

Wskazówki praktyczne

Aby stworzyć wspólny interfejs warto zaimplementować klasę z metodami wirtualnymi która będzie częścią wspólną dla niewspółbieżnych klas. Adapter jest używany w przypadku gdy chcemy przysłonić już istniejące interfejsy jednym wspólnym, a nie możemy tego zrobić np. w sytuacji używania bibliotek zewnętrznych do których mamy tylko API. Autorzy często przytaczają przykład różnych wejść (HDMI, VGA) które mają takie same zadania ale różne interfejsy, a klient ma obsługiwać takie same metody (wyświetl, odepnij).

Zalety i wady

Zalety

  • Umożliwia współprace klas których wykorzystanie byłoby utrudnione ze względu na brak spójnych interfejsów.
  • Bardziej przejrzysty kod

Wady:

  • Wymagane jest dziedzicznie co powoduje przyrost plików z klasami (jeżeli stosujemy adapter klasowy)
  • Adapter klasowy jest mniej elastyczny niż Adapter obiektowy np. po dodaniu w naszym przykładzie getScreenShot(), zakrywanie metod wirtualnych jest bezsensowne w przypadku Mp3Player
#include <QDebug>
#include <QString>

class Player
{
    public:
        virtual void play(){}
        virtual void stop(){}
};

class FlashPlayer: public Player
{
    public:
        void play(){ qDebug() << "Play flash file"; }
        void stop(){ qDebug() << "Stop flash file"; }
};

// This is liblary and we cannot change implementatnion
class Mp3Player
{
    public:
        void playSound(){ qDebug() << "Play mp3 file"; }
        void stopSound(){ qDebug() << "Stop mp3 file"; }
};

/* Adapter */
class Mp3Adapter : public Mp3Player, public Player
{
public:
    void play(){playSound();}
    void stop(){stopSound();}

};

int main()
{
    Player *flash = new FlashPlayer();
    //  Player *mp3 = new Mp3Player();  // Błąd !!!
      Player *mp3 = new Mp3Adapter();

    QList <Player *> listPlayers{flash,mp3};

    foreach(Player *play, listPlayers)
        play->play();


    foreach(Player *play, listPlayers)
        play->stop();

    qDeleteAll(listPlayers);

    return 0;
}

Wyjście programu:

Play flash file
Play mp3 file
Stop flash file
Stop mp3 file
Wzorzec Fabryka abstrakcyjna i Metoda wytwórcza C++/Qt

Wzorzec Fabryka abstrakcyjna i Metoda wytwórcza C++/Qt

Omówienie wzorca projektowego „Fabryka abstrakcyjna” na przykładach C++.

Wzorzec projektowy Singleton C++ / Qt

Wzorzec projektowy Singleton C++ / Qt

Zastosowanie Kreacyjny wzorzec projektowy, charakteryzujący się jedną instancją danego obiektu oraz globalnym dostępem do funkcji getInstance(), dzięki czemu możemy uzyskać do niego dostęp praktycznie z każdego miejsca. Inną cechą charakterystyczną jest Lazy loading, czyli alokacja pamięci dla singletona występuje dopiero przy jego pierwszym wywołaniu (odwołaniu […]

Wzorzec Budowniczy C++/Qt

Wzorzec Budowniczy C++/Qt

Budowniczy

Wzorzec Budowniczy to wzorzec kreacyjny zapewniający kontrolę nad procesem tworzenia klas. Jest on przydatny, gdy chcemy zastosować wiele różnych konstruktorów, zapewniając większą czytelność kodu.

builder_uml_01

Elementy charakterystyczne

W tym wzorcu możemy wyróżnić następujące elementy:
Budowniczy – interfejs abstrakcyjny do tworzenia części składowych obiektu złożonego, w naszym przykładzie jest to klasa Pizza
(produktu)
Konkretny budowniczy – jego celem jest konstruowanie i zestawianie części produktu poprzez implementowanie interfejsu Budowniczego. Definiuje i kontroluje on tworzoną przez siebie
reprezentację. Konkretnych budowniczych może być wiele, w naszym przykładzie jest to HawajskaPizza, OstraPizza i MexicoPizza.
Dyrektor – konstruuje obiekty, używając interfejsu Budowniczego do wywoływania metod konkretnego budowniczego oraz nadzoruje proces budowy aby proces konstrukcyjny przebiegał w odpowiedniej sekwencji. W naszym przypadku jest to kelner.
Produkt – złożony obiekt który tworzony jest z wielu części składowych. Jest on konstruowany przez Dyrektora przy użyciu konkretnego budowniczego. W naszym przypadku jest to Pizza którą zwaraca getProduct();

Zalety

  • Różnorodność implementacji wewnętrznych struktur klas.
  • Łatwość konwersji tych samych danych do kilku różnych postaci. Np. jeden format tekstu na różne typy wyjściowe PDF, HTML, Plain text.
  • Duża skalowalność dzięki elastyczności w modyfikacjach (dodawanie nowych reprezentacji klas jest uproszczone). Gdy Chcemy sobie zagwarantować możliwość łatwego dodawania obsługi nowego formatu danych wyjściowych, zapobiegając jednocześnie jakimkolwiek modyfikacjom klasy zarządzającej obiektami budowniczymi.
  • Większa możliwość kontrolowania tego, w jaki sposób tworzony jest obiekt (proces konstrukcyjny jest niezależny od elementów, z których składa się tworzony obiekt.

Wady

  • Duża liczba obiektów reprezentujących konkretne produkty.
  • Redundancja – nieumiejętne używanie wzorca może spowodować nieczytelność kodu (jeden produkt może tworzony przez zbyt wielu budowniczych).

Zastosowanie

Wzorzec budowniczego stosowany jest do oddzielenia sposobu tworzenia obiektów od tego jak te obiekty mają wyglądać. Używamy go wtedy gdy obiekty różnią się finalnie, ale zawierają takie same elementy i chcemy je poskładać z takich samych części np. gdy składamy komputer to robimy to z różnych elementów, ale finalnie osiągamy ten sam produkt – komputer. Tak samo jest ze składaniem samochodów ( rożne silniki, amortyzatory, światła), jadłospisów (różne elementy tj. ziemiaki z mięsem lub ryż z mięsem, różne rodzaje surówek).

#include <QDebug>
#include <QString>
#include <QList>

class Pizza
{
public:
    enum SKLADNIK{
        PIECZARKI = 1,
        SER = 2,
        SZYNKA = 4,
        PEPERONI = 8,
        KUKURYDZA = 16,
        TUNCZYK = 32,
        KURCZAK = 64,
        BROKULY = 128,
        JAJKO = 256,
        CEBULA = 512,
        ANANAS = 1024,
        OREGANO = 2048,
        FASOLA = 4096,
        SALAMI = 8192
    };

    enum SOS{
        CZOSNKOWY = 1,
        POMIDOROWY = 2,
        OLIWA = 4
    };

    const QString getSkladniki(const int skladnik)
    {
                switch(skladnik)
                {
                case PIECZARKI:
                    return "Pieczarki";
                case SER:
                    return "Ser";
                case SZYNKA:
                    return "Szynka";
                case PEPERONI:
                    return "Peperoni";
                case KUKURYDZA:
                    return "Kukurydza";
                case TUNCZYK:
                    return "Tuńczyk";
                case KURCZAK:
                    return "Kurczak";
                case BROKULY:
                    return "Brokuły";
                case JAJKO:
                    return "Jajko";
                case CEBULA:
                    return "Cebula";
                case ANANAS:
                    return "Ananas";
                case SALAMI:
                    return "Salami";
                case FASOLA:
                    return "Fasola";
                case OREGANO:
                    return "Oregano";
                default:
                    return "Niezdefiniowany";
                }
    }

    const QString getSosy(const int sos)
    {
                switch(sos)
                {
                case CZOSNKOWY:
                    return "Czosnkowy";
                case POMIDOROWY:
                    return "Pomidorowy";
                case OLIWA:
                    return "Oliwa";
                default:
                    return "Niezdefiniowany";
                }
    }

private:
    QString nazwa;
    bool ciasto;
    int sos;
    int skladniki;

public:
    Pizza() { }
    ~Pizza() { }

    void setCiasto(bool grube = false)
    {
        ciasto = grube;
    };
    void setSos(const int sklad) { this->sos = sos; };
    void setDodatki(const int sklad) { skladniki = sklad;  };
    void setDodatkiNowe(const int sklad) { skladniki += sklad;  };
    void setNazwa(const QString &value) { nazwa = value; };

    void showPizza()
    {
        QString nazwy;
        QString sosy;
        for(int i = 1; i <= SALAMI;i*=2)
            if(i & skladniki)
                nazwy += (nazwy.isEmpty() ? "" : ", ") + getSkladniki(i);

        for(int i = 1; i <= OLIWA;i*=2)
            if(i & skladniki)
                sosy += (sosy.isEmpty() ? "" : ", ") + getSosy(i);

        qDebug() << "Pizza" << nazwa
                 << " z grubym ciastem: " << (ciasto ? "Tak" : "Nie")
                 << "\nSos: " << sosy
                 << " Dodatki " << nazwy << "\n";
    }
};
// Builder
class PizzaBuilder
{
protected:
    Pizza * pizza;
public:
    PizzaBuilder() {}
    virtual ~PizzaBuilder() {}
    Pizza *getPizza() { return pizza; }

    void createNewPizzaProduct() { pizza = new Pizza; }

    virtual void buildNazwa()=0;
    virtual void buildCiasto()=0;
    virtual void buildSos()=0;
    virtual void buildDodatki()=0;

};

class HawajskaPizza : public PizzaBuilder
{
public:
    HawajskaPizza() : PizzaBuilder() {}
    ~HawajskaPizza(){}

    void buildNazwa() { pizza->setNazwa("Hawajska"); };
    void buildCiasto() { pizza->setCiasto(true); }
    void buildSos() { pizza->setSos(Pizza::CZOSNKOWY); }
    void buildDodatki() { pizza->setDodatki(Pizza::SER | Pizza::SZYNKA | Pizza::ANANAS  | Pizza::OREGANO); }
};
class OstraPizza : public PizzaBuilder
{
public:
    OstraPizza() : PizzaBuilder() {}
    ~OstraPizza() {}

    void buildNazwa() { pizza->setNazwa("Ostra"); };
    void buildCiasto() { pizza->setCiasto(false); }
    void buildSos() { pizza->setSos(Pizza::CZOSNKOWY | Pizza::POMIDOROWY); }
    void buildDodatki() { pizza->setDodatki(Pizza::SER | Pizza::CEBULA | Pizza::KUKURYDZA | Pizza::OREGANO); }
};

class MexicoPizza : public PizzaBuilder
{
public:
    MexicoPizza() : PizzaBuilder() {}
    ~MexicoPizza() {}

    void buildNazwa() { pizza->setNazwa("Meksykańska"); };
    void buildCiasto() { pizza->setCiasto(true); }
    void buildSos() { pizza->setSos(Pizza::OLIWA); }
    void buildDodatki() { pizza->setDodatki(Pizza::SER | Pizza::PEPERONI | Pizza::SALAMI | Pizza::FASOLA); }
};

// Director
class Kelner
{
private:
    PizzaBuilder* pizzaBuilder;
public:
    Kelner() : pizzaBuilder(NULL) {}
    ~Kelner() { }

    void setPizzaBuilder(PizzaBuilder* b) { pizzaBuilder = b; }
    Pizza* getPizza() { return pizzaBuilder->getPizza(); }
    void constructPizza()
    {
        pizzaBuilder->createNewPizzaProduct();
        pizzaBuilder->buildNazwa();
        pizzaBuilder->buildCiasto();
        pizzaBuilder->buildSos();
        pizzaBuilder->buildDodatki();
    }
};


int main()
{
    Kelner kelner;

    HawajskaPizza hawajskaPizza;
    kelner.setPizzaBuilder (&hawajskaPizza);
    kelner.constructPizza();
    Pizza* pizza = kelner.getPizza();
    pizza->showPizza();

    OstraPizza ostraPizza;
    kelner.setPizzaBuilder(&ostraPizza);
    kelner.constructPizza();
    pizza = kelner.getPizza();
    pizza->showPizza();

    MexicoPizza mexicoPizza;
    kelner.setPizzaBuilder(&mexicoPizza);
    kelner.constructPizza();
    kelner.getPizza()->setDodatkiNowe(Pizza::KURCZAK);
    pizza = kelner.getPizza();
    pizza->showPizza();

    return EXIT_SUCCESS;
}
Generating random number using srand() and rand() Qt

Generating random number using srand() and rand() Qt

You can use random function from stdlib and fix time to maximize pseudo random operation in a short period of short time. const int MainWindow::getNumber() const { qsrand( (unsigned)time(NULL) ^random()); return qrand() % max; } Using qsrand(QTime::currentTime().msec()) it can also be done, but in a […]

Recenzja książki „C++ i Qt – wprowadzenie do wzorców projektowych”

Recenzja książki „C++ i Qt – wprowadzenie do wzorców projektowych”

Książkę można byłoby zawrzeć w jednym zdaniu – jest to zdecydowanie najlepsza pozycja o Qt, którą czytałem. Choć zdjęcie wygląda, jakbym ją wypożyczył z biblioteki, gdzie była czytana co najmniej przez kilkadziesiąt osób, to jednak muszę przyznać, że jest to książka którą czytałem sam wielokrotnie, […]

Recenzja książki „Myśl jak programista”

Recenzja książki „Myśl jak programista”

Mysl Jak Programista

Książka ukazuje obrazowo, jak alokowana jest pamięć na stercie i stosie. Wskazuje również zalety programowania rekurencyjnego, jednak zarazem zawiera zbyt wiele powtórzeń. Autor położył nacisk na rozwiązywanie problemów w schematyczny sposób oraz przedstawił kłopotliwe sytuacje, w jakich może znaleźć się programista.

Książka nie jest raczej skierowana do zaawansowanych programistów. Autor porusza podstawowe zagadnienia dotyczące zarządzania pamięcią. Jednak należy przyznać, że jest to dość istotna kwestia podczas pierwszych lekcji związanych z programowaniem. Dodatkowo autor przedstawia obrazowo takie zagadnienia, jak tablice, listy, klasy oraz sortowanie.

REKOMENDACJA

Książkę poleciłbym raczej początkującym programistom C++.

OCENA

Książkę oceniam: 5/10.