pomoc w programie "Estymator pracy"

0

Hi!
Jestem na początku swojej drogi w programowaniu w C++
Przerabiając książkę napotkałem w rozdz.6 'Funkcje' zadanie do zrobienia "Estymator pracy malarskiej" Od użytkownika należy pobrać ilość pokoi, ilość metrów[2] w każdym pokoju oraz cenę za 1 litr farby. W zadaniu określone jest, że na każde 60m2 ściany potrzeba jest 1 litr farby oraz 8h godzin pracy.
Oplata za godzinę pracy wynosi 25zl.
Postanowiłem sobie utrudnić zadanie i nie pisać kodu za pomocą procedur tylko użyć Klasy (<- dopiero będę przerabiać w rozdz.13)
Stworzyłem sobie na początek oto taki mały program.
Chciałbym skorzystać z waszego doświadczenia oraz poprosić o pomoc.

  1. Czy moglibyście udzielić mi wskazówek i napisać co jest w nim do poprawy?
  2. Czy ktoś może wyjaśnić, co oznacza to ostrzeżenie
    warning: padding class 'Estymator' with 4 bytes to align 'metry_kwadratowe'
    i jak mam się do niego odnieść?
  3. Czy zaimplementowany w tej klasie konstruktor i destruktor jest poprawny?
  4. Jak zamienić double na godziny i minuty?
    Zadanie wymaga tylko wypisania całkowitego kosztu pracy, ale dla weryfikacji
    wyświetlam sobie dodatkowe informacje m.in czas. I tutaj są dziwne rzeczy.
    ogólne program daje poprawne wyniki np. dla
    2 pokoi po 30m2 każdy i 10zł za 1 litr farby daje 8 godni pracy
    1 pokój 15m2 10zł za litr farby daje 2 godziny pracy
    1 pokój 30m2 10zł za litr farby daje 4 godziny pracy
    ale dla np
    1 pokój 44m2 10zł za litr farby daje 5,87h pracy <- i to mnie niepokoi
    Wszelkie uwagi/sugestie mile widziane.
    Poniżej moje rozwiązanie
#include <iostream>
#include <iomanip>
#include <cstring> 

using namespace std;

class Estymator
{
private:
    static const int stawka_godziny_pracy = 25;
    int liczba_pokoi;
    double metry_kwadratowe, suma_metrow_kwadratowych;
    double ilosc_litrow_farby;
    double cena_litra_farby;
    double ilosc_godzin;
    double calkowity_koszt_malowania, calkowity_koszt_farby;
    double koszt_pracy;
public:
    Estymator(){}
    Estymator(int lp, double smk, double clf)
    {
        this->liczba_pokoi = lp;
        this->suma_metrow_kwadratowych = smk;
        this->cena_litra_farby = clf;
    }
    ~Estymator(){}
    void setLiczbaPokoi(int);
    double getLiczbaPokoi() const;
    void setMetry_kwadratowe_pokoju(int);
    double getMetry_kwadratowe_pokoju() const;
    void setCena_litra_farby(double);
    double getCena_litra_farby() const;
    void podsumowanie();
};

void Estymator::setLiczbaPokoi(int lp)
{
    liczba_pokoi = lp;
}
double Estymator::getLiczbaPokoi() const
{
    return liczba_pokoi;
}
void Estymator::setCena_litra_farby(double clf)
{
    cena_litra_farby = clf;
}
double Estymator::getCena_litra_farby() const
{
    return cena_litra_farby;
}
void Estymator::podsumowanie()
{
    cout << "\n\t\tPodsumowanie" << "\n";
    cout << "\tLiczba pokoi: " << liczba_pokoi << endl;
    cout << "\tCalkowita suma [m]2 : " << suma_metrow_kwadratowych << endl;
    cout << "\tCena 1 litra farby wynosi: " << cena_litra_farby << " zl" << endl;
    //na 60m2 = 1l farby + 8h godzin pracy oplata za godzinepracy 25zl
    ilosc_litrow_farby = suma_metrow_kwadratowych / 60;
    ilosc_godzin = ilosc_litrow_farby * 8;
    calkowity_koszt_farby = ilosc_litrow_farby * cena_litra_farby;
    koszt_pracy = ilosc_godzin * stawka_godziny_pracy;
    calkowity_koszt_malowania = koszt_pracy + calkowity_koszt_farby;
    cout << "\tCalkowita ilosc godzin pracy : " << ilosc_godzin << endl;
    cout << "\tCalkowita szacunkowa cena tego malowania wynosi : " << calkowity_koszt_malowania << " zl" << endl;
}

void Estymator::setMetry_kwadratowe_pokoju(int lp)
{
    suma_metrow_kwadratowych = 0; //reset
    for(int i = 0; i < lp; ++i)
    {
        cout << "Ile m[2] w " << i+1 << " pomieszczeniu: ";
        cin >> metry_kwadratowe;
        suma_metrow_kwadratowych += metry_kwadratowe;
    }
}
double Estymator::getMetry_kwadratowe_pokoju() const
{
    return suma_metrow_kwadratowych;
}


int main()
{
    cout << fixed << setprecision( 2 );
    cout << "\t\t\tEstymator pracy malarskiej" << endl;

    char znak;
    Estymator obj, *inz;
    int liczba_pokoi = 0;
    double cena_litra_farby = 0;

    inz = new Estymator(1,60,10);
    inz->podsumowanie();
    delete inz;
    cout << "\n";

    while(1)
    {
        cout << "Ile pokoi do pomalowania: ";
        cin >> liczba_pokoi;

        obj.setLiczbaPokoi(liczba_pokoi);
        obj.setMetry_kwadratowe_pokoju(liczba_pokoi);

        cout << "Cena za 1 litr farby: ";
        cin >> cena_litra_farby;

        obj.setCena_litra_farby(cena_litra_farby);
        obj.podsumowanie();

        cout << "\n\t\tZnak 'q' konczy program. Kontynuowac ? ";
        cin >> znak;
        if(znak == 'q') break;

    }//end loop while

    cout << "\t\tKoniec programu." << endl;
    getchar();
    return 0;
}
1

@WWA2025:

  1. To oznacza, że kompilator wyrównał rozmiar klasy w pamięci dodając 4 bajty. Używasz w niej typu double, który ma 8 bajtów, masz też jednego inta, któr zajmuje 4 bajty.
    To jest optymalizacja, wyrównując rozmiar obiektu do konkretnej wielokrotności - w tym przpadku 8 - umożliwiony jest szybszy dostęp do pamięci.

  2. Definicja destruktora jest pusta, więc nie ma za bardzo do czego się przyczepić.

  3. Zawsze możesz zamienić tę wartość na sekundy i ją podzielić na HS

4

setLiczbaPokoi - od tego można dostać raka oczu :P

Nie będę się upierać, żebyś miał angielskie nazwy (chociaż w profesjonalnych projektach to raczej jest taki standard), ale weź kolego wybierz jedną konwencje i się jej trzymaj. Albo po polsku - wtedy okreslLiczbePokoi albo angielskie - setRoomCount.

Takie potworki miksujące dwa języki są paskudne, podobne do tego:


void Estymator::setLiczbaPokoi(int lp)
{
liczba_pokoi = lp;
}
double Estymator::getLiczbaPokoi() const
{
return liczba_pokoi;
}

Pytanie - po co wprowadziłeś tam settery/gettery? Bo o ile widzę, to one (poza przypisaniem/odczytaniem wartości) nic nie robią. Równie dobrze mógłbyś po prostu się odwoływać bezpośrednio do liczba_pokoi, wyszłoby na to samo. W ogóle - co do zasadności stosowania setterów/getterów zdania są podzielone, warto żebyś się zapoznał się z paroma wątkami z forum, gdzie to było poruszane:

Do czego służą gettery i settery?
Java. Gettery i Settery.
Jedna metoda zamiast dwóch (gettery, settery)
Po co gettery i settery?

Poza tym jeszcze do tego kawałka mam jedną uwagę:
najpierw mamy int liczba_pokoi; - czyli zakładamy, że jest to integer. setLiczbaPokoi przyjmuje także int, ale już getLiczbaPokoi zwraca double (chociaż wewnętrznie na swoje potrzeby pobiera tego inta). Tak ma być celowo, czy to przeoczenie?

Postanowiłem sobie utrudnić zadanie i nie pisać kodu za pomocą procedur tylko użyć Klasy (<- dopiero będę przerabiać w rozdz.13)

Z jednej strony fajnie, że podchodzisz ambitnie do tematu, ale z drugiej - nie ma co wychodzić przed szereg. To trochę jakby ktoś uznał na kursie na prawo jazdy że już umie parkować na placu, więc od razu jedzie Transitem na autostradę ;) Po kolei, ze spokojem, nie jesteś w szkole żebyś musiał Pani imponować i zbierać dodatkowe punkty za aktywność. Lepiej jedź powoli, ale ze zrozumieniem, zgodnie z materiałem książki/kursu z którego korzystasz.

setMetry_kwadratowe_pokoju

Tutaj podobna uwaga do pierwszej - czyli masz mieszanie konwencji.
Jest kilka popularnych sposobów nazywania zmienych/funkcji, z czego chyba najczęściej stosowaną jest tzw. camelCase - https://pl.wikipedia.org/wiki/CamelCase. Staraj się trzymać jednej konwencji - albo masz wielkie litery na początku każdego wyrazu - wtedy byśmy mieli setMetryKwadratowePokoju albo z podkreślnikiem (nie polecam takiego rozwiązania) - wtedy set_metry_kwadratowe_pokoju.

Skoro chcesz podejść ambitnie do tematu (nawiązanie do przeskoczenie do przodu z materiałem) to mam pomysł, jak możesz sobie ambitnie rozwinąć ten program. Na razie masz po prostu powierzchnię pokoju - ale przecież każde pomieszczenie może mieć inny metraż. Jak chcesz to pokombinuj, jak to zrobić - żeby program pytał o ilość pomieszczeń, potem o metraż każdego z nich z osobna, a następnie robił wycenę malowania całego mieszkania.

Nieaktualna uwaga, moje przeoczenie, nie było tematu :D :D

Jak zamienić double na godziny i minuty?
[...]
daje 5,87h pracy <- i to mnie niepokoi

No to co do 5h nie mamy wątpliwości, zostaje kwestia minut.
Nie podam Ci gotowego rozwiązania, ale sposób, jak ja bym to zrobił :P
Skoro mamy 60 minut w godzinie, a teraz nam wyszło 0,87 godziny, to po pomnożeniu 60 * 0,87 dostajemy 52 minuty.
Czy teraz jest wszystko jasne?

0
WWA2025 napisał(a):

Postanowiłem sobie utrudnić zadanie i nie pisać kodu za pomocą procedur tylko użyć Klasy (<- dopiero będę przerabiać w rozdz.13)

I co z tego, że w klasie zawarłeś "wszystko co się rusza" ?
To jest bardzo dalekie od programowania obiektowego, anty-OOP

1

na początek dziękuję za poświęcony czas

@Eldorad O.
rozumiem, że nie muszę się za bardzo przejmować takimi ostrzeżeniami.

@cerrato
jeżeli chodzi o nazwy zmiennych to faktycznie trochę nietrafione

Nie będę się upierać, żebyś miał angielskie nazwy (chociaż w profesjonalnych projektach to raczej jest taki standard),

czytam polskie wydanie książki, więc używam polskich nazw, tym bardziej że jednostką anglosaską jest galon a nie litr, jakbym napisał galon to zaraz by było czy angielski czy h-amerykański D

Pytanie - po co wprowadziłeś tam settery/gettery?

Posiłkowałem się książką, więc jeszcze tego dobrze nie rozumiem, ale dziękuję za linki z materiałem, Przeczytam i zgłębię temat.

zwraca double (chociaż wewnętrznie na swoje potrzeby pobiera tego inta). Tak ma być celowo, czy to przeoczenie?

przeoczenie z mojej strony, dlatego dałem kod im więcej oczu patrzy tym można więcej błędów wychwycić i poprawić

Jak chcesz to pokombinuj, jak to zrobić - żeby program pytał o ilość pomieszczeń, potem o metraż każdego z nich z osobna, a następnie robił wycenę malowania całego mieszkania.

dokładnie to robi

Skoro mamy 60 minut w godzinie, a teraz nam wyszło 0,87 godziny, to po pomnożeniu 60 * 0,87 dostajemy 52 minuty.
Czy teraz jest wszystko jasne?

Tak zrozumiałem. Dziękuję.

@Stój Halina

I co z tego, że w klasie zawarłeś "wszystko co się rusza" ?
To jest bardzo dalekie od programowania obiektowego, anty-OOP

Od czegoś trzeba zacząć

1

Brakuje mi tutaj jawnej informacji ile można pomalować m2 ścian w ciągu jednej godziny. Z kodu można wywnioskować że jest to czynnik równy 7.5

1

Pierwsze i najważniejsze. NIE-UŻYWAJ-NEW-I-DELETE. https://dsp.krzaq.cc/post/176/ucze-sie-cxx-kiedy-uzywac-new-i-delete/

A co do Twoich pytań:
ad.2 nie przejmowałbym się. Jak nie optymalizujesz pod performance to bym ten warning wyłączył, bo imho generuje on tylko "szum informacyjny", ale zrobisz jak zechcesz.
ad. 3 Lepszą opcją jest ~Estymator() = default; Tzn. efektywnie to będzie to samo, ale default imho podniesie czytelność. Ponadto:
static const int costam = 1234; zamieniłbym na static constexpr int = 1234;
Co bym przemyślał to design. Fajnie, że chcesz uczyć się OOP, niemniej estymator imho powinien przyjmować dane wejściowe, które możesz podzielić bardziej i potem powinien zwrócić wartość. Printować ma jakiś printer.
De facto, ten estymator to powinna być funkcja/objekt funkcyjny, która przyjmuje, nie wiem, powierzchnię mieszkania, cenę farby, cenę za godzinę malarza itd. On (estymator, nie malarz ;) ) powinien zwrócić wynik, wypisywać go powinien jakiś printer, czyli u Ciebie zamiast obj.podsumowanie() powinno być coś w stylu std::cout << obj.podsumowanie() << '\n';. Ew. obj.wypiszPodsumowanie(std::cout) (a jeszcze lepiej printSummary, ale to osobna rzecz).

Dalej: nazewnictwo: różne są konwencje, ale bezpiecznie wyjść od zasady pole klasy = rzeczownik, funkcja/metoda = czasownik, stała WIELKIE_LITERY. Polecam też wszystko po angielsku od razu robić.

Poza tym, jak masz setter i getter to w praktyce masz pole publiczne. By convention można robić w setterze walidację czy wyliczenia, ale lepiej zrobić osobną klasę żeby po prostu podmienić obiekt na nowy a walidować będzie konstruktor/factory. Natomiast błędem imho jest odczyt w setterze, od tego powinien być jakiś reader albo po prostu odpowiednio przeładowany operator >>.

Powodzenia ;)

1

@TomaszLiMoon

Brakuje mi tutaj jawnej informacji ile można pomalować m2 ścian w ciągu jednej godziny.

W treści zadania nie ma tego. Jest jasno sprecyzowane że "Firma malarska określiła, że na każde 60m2 ściany potrzeba jest 1 litr farby i 8h godzin pracy. Opłata za godzinę pracy wynosi 25zł."

#alagner wezmę Twoje uwagi a także uwagi @cerrato zmodyfikuję kod w takim stopniu w jakim będę potrafił i umieszczę go na forum

0

Wprowadziłem trochę poprawek, ale nie wiem czy do końca o to chodzi

#include <iostream>
#include <iomanip>
#include <cstring>      // strlen
#include <cmath>        //round, abs, fabs

using namespace std;

class Kosztorys
{
private:
    //static constexpr int stawka_za_godzine_pracy = 25; //incompatible with c++98
    static const int stawka_za_godzine_pracy = 25;
    int liczba_pokoi, godzina;
    double minut;
    double metry_kwadratowe, suma_metrow_kwadratowych;
    double ilosc_litrow_farby;
    double cena_litra_farby;
    double ilosc_godzin;
    double calkowity_koszt_malowania, calkowity_koszt_farby;
    double koszt_pracy;
public:
    Kosztorys(){}
    Kosztorys(int lp, double smk, double clf)
    {
        this->liczba_pokoi = lp;
        this->suma_metrow_kwadratowych = smk;
        this->cena_litra_farby = clf;
    }
    //~Kosztorys() = default; //incompatible with c++98
    ~Kosztorys(){}
    int liczba_pokojow_do_malowania(int lp);
    double calkowita_suma_metrow_kwadratowych_do_pomalowania(int);
    double cene_za_jeden_litr_farby(double);
    double szacunkowa_wycena(double, double);
    double zaokraglenie_do_setnych(double);
    int tylko_godzina(double);
    double tylko_minuty(double,int);
    friend ostream& operator<<(ostream & os, Kosztorys & m);
};
int Kosztorys::tylko_godzina(double lg)
{
    ilosc_godzin = lg;
    godzina = static_cast<int>( zaokraglenie_do_setnych(ilosc_godzin) ); //type conversions
    return godzina;
}
double Kosztorys::tylko_minuty(double lg, int h)
{
    ilosc_godzin = lg;
    godzina = h;
    minut = (60 * (ilosc_godzin - godzina));
    return minut;
}
double Kosztorys::szacunkowa_wycena(double smk, double clf)
{
    /*na pomalowanie 60m2 potrzeba jest 1l farby i 8h godzin pracy
    oplata za godzinepracy 25zl */

    suma_metrow_kwadratowych = smk;
    cena_litra_farby = clf;

    ilosc_litrow_farby = suma_metrow_kwadratowych / 60;
    ilosc_godzin = ilosc_litrow_farby * 8;
    calkowity_koszt_farby = ilosc_litrow_farby * cena_litra_farby;
    koszt_pracy = ilosc_godzin * stawka_za_godzine_pracy;
    calkowity_koszt_malowania = koszt_pracy + calkowity_koszt_farby;

    tylko_godzina(ilosc_godzin);
    tylko_minuty(ilosc_godzin,godzina);

    return calkowity_koszt_malowania;
}
double Kosztorys::zaokraglenie_do_setnych(double x)
{
    long int wynik = static_cast<int>(fabs(x * 1000)); //rzutowanie
    if (wynik % 10 >= 5) abs(wynik += 10);
    return fabs((wynik / 10) * 0.01);
}

int Kosztorys::liczba_pokojow_do_malowania(int lp)
{
    liczba_pokoi = lp;
    return liczba_pokoi;
}
double Kosztorys::calkowita_suma_metrow_kwadratowych_do_pomalowania(int lp)
{
    suma_metrow_kwadratowych = 0; //reset
    for(int i = 0; i < lp; ++i)
    {
        cout << "\tHow many m[2] in the " << i+1 << " room: ";
        cin >> metry_kwadratowe;
        suma_metrow_kwadratowych += metry_kwadratowe;
    }
    return suma_metrow_kwadratowych;
}

double Kosztorys::cene_za_jeden_litr_farby(double clf)
{
    cena_litra_farby = clf;
    return cena_litra_farby;
}
ostream & operator<<(ostream & os, Kosztorys & m)
{
        os << "\n\t\tPodsumowanie "<< "\n";
        os << "\tLiczba_pokoi: " << m.liczba_pokoi << "\n";
        os <<  "\tCalkowita suma [m]2 : " << m.suma_metrow_kwadratowych << "\n";
        os << "\tCena litra farby : " << m.cena_litra_farby << " zl" << "\n";
        //os << "\tCalkowita ilosc godzin pracy : " << m.ilosc_godzin << "\n";
        os << "\tCalkowita ilosc godzin pracy : ";
        //type conversions int(m.minute)
        (static_cast<int>(m.minut) == 0) ? os << m.godzina << " godzin" << "\n" : os << m.godzina << " godzin i " << fixed << setprecision( 0 ) << m.minut << " minut" << "\n";
        cout << fixed << setprecision( 2 );
        os << "\tCalkowita szacunkowa cena tego malowania wynosi : " << m.calkowity_koszt_malowania << " zl" << endl;
        return os;
}

int main()
{
    cout << fixed << setprecision( 2 );
    cout << "\t\t\tKosztorys prac malarskich" << endl;

    char znak;
    int liczba_pokoi = 0;
    double cena = 0, suma_metrow_kwadratowych = 0;
    Kosztorys obj, test(1,60,10.20);
    test.szacunkowa_wycena(60,10.20);
    std::cout << test << '\n';

    while(1)
    {
        cout << "\n\tIle pokoi do pomalowania : ";
        cin >> liczba_pokoi;

        obj.liczba_pokojow_do_malowania(liczba_pokoi);
        suma_metrow_kwadratowych = obj.calkowita_suma_metrow_kwadratowych_do_pomalowania(liczba_pokoi);

        cout << "\tIle kosztuje 1 litr farby : ";
        cin >> cena;
        obj.cene_za_jeden_litr_farby(cena);

        //obliczenia
        obj.szacunkowa_wycena(suma_metrow_kwadratowych,cena);
        //wypisz
        std::cout << obj << '\n';

        cout << "\n\t\tLiterka 'q' konczy program. Kontynowac? ";
        cin >> znak;
        if(znak == 'q') break;

    }//end loop while

    cout << "\t\tKoniec programu." << endl;
    getchar();
    return 0;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1